mod_jk Configuration — From Installation to JkMount
mod_jk was the standard method for legacy Apache+Tomcat integration. It is no longer recommended for new projects, but understanding its configuration is necessary for maintaining existing systems.
Installing mod_jk
Ubuntu/Debian
# Install via APT (simplest method)
sudo apt install libapache2-mod-jk
# Verify installation
apache2ctl -M | grep jk
# jk_module (shared)
CentOS/RHEL
# Requires EPEL repository
sudo dnf install epel-release
sudo dnf install mod_jk
# Module file location
ls /etc/httpd/modules/mod_jk.so
Compile from Source (Latest Version)
# Dependencies
sudo apt install -y build-essential apache2-dev
# Download source
cd /tmp
wget https://dlcdn.apache.org/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.49-src.tar.gz
tar -xzf tomcat-connectors-1.2.49-src.tar.gz
cd tomcat-connectors-1.2.49-src/native
# Compile
./configure --with-apxs=/usr/bin/apxs
make
sudo make install
# Verify
ls /usr/lib/apache2/modules/mod_jk.so
workers.properties Configuration
workers.properties is the core configuration file for mod_jk, where Tomcat instances (workers) are defined.
# /etc/apache2/workers.properties
# === Single Tomcat Worker ===
worker.list=worker1
# Worker type: ajp13 (AJP/1.3)
worker.worker1.type=ajp13
worker.worker1.host=127.0.0.1
worker.worker1.port=8009
# Connection settings
worker.worker1.connection_pool_size=10 # Connection pool size
worker.worker1.connection_pool_timeout=600 # Idle connection timeout (seconds)
worker.worker1.socket_timeout=300 # Socket timeout (seconds)
worker.worker1.socket_keepalive=true # TCP keepalive
# Retry settings
worker.worker1.retries=2
worker.worker1.recovery_options=7 # Auto-recover on errors
Load Balancing Worker Configuration
# /etc/apache2/workers.properties
# Individual Tomcat instances
worker.list=lb_worker,tomcat1,tomcat2
worker.tomcat1.type=ajp13
worker.tomcat1.host=127.0.0.1
worker.tomcat1.port=8009
worker.tomcat1.lbfactor=1 # Weight (higher = more requests)
worker.tomcat2.type=ajp13
worker.tomcat2.host=192.168.1.11
worker.tomcat2.port=8009
worker.tomcat2.lbfactor=1
# Load balancer worker
worker.lb_worker.type=lb
worker.lb_worker.balance_workers=tomcat1,tomcat2
worker.lb_worker.method=R # R=Round Robin, T=Traffic, B=Busyness
worker.lb_worker.sticky_session=true # Enable sticky sessions
worker.lb_worker.sticky_session_force=false # Fail over to another node on failure
Apache Configuration — Loading mod_jk and JkMount
# /etc/apache2/conf-available/mod-jk.conf
# Load module
LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
# Path to workers.properties
JkWorkersFile /etc/apache2/workers.properties
# Log settings
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel warn # info, warn, error
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# Request/response log (for debugging, disable in production)
JkRequestLogFormat "%w %V %T"
# Enable configuration
sudo a2enconf mod-jk
sudo systemctl reload apache2
Using JkMount in VirtualHost
# /etc/apache2/sites-available/myapp.conf
<VirtualHost *:80>
ServerName example.com
# Forward all requests to worker1
JkMount /* worker1
# Static files served by Apache (JkUnMount)
JkUnMount /static/* worker1
JkUnMount /images/* worker1
JkUnMount /css/* worker1
JkUnMount /js/* worker1
# Static file directory
Alias /static /var/www/myapp/static
<Directory "/var/www/myapp/static">
Options -Indexes
Require all granted
</Directory>
# Access log
CustomLog ${APACHE_LOG_DIR}/myapp_access.log combined
ErrorLog ${APACHE_LOG_DIR}/myapp_error.log
</VirtualHost>
Sticky Session Configuration
In a clustered environment, ensures the same client always routes to the same Tomcat instance.
Tomcat server.xml Configuration
<!-- Set unique jvmRoute for each Tomcat instance -->
<!-- Tomcat 1: server.xml -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<!-- Tomcat 2: server.xml -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
workers.properties Sticky Sessions
worker.lb_worker.sticky_session=true
# JSESSIONID example: abc123.tomcat1 (the .tomcat1 suffix is the routing key)
# worker.worker1.route=tomcat1 (explicit routing key)
worker.tomcat1.route=tomcat1
worker.tomcat2.route=tomcat2
mod_jk Status Page
The mod_jk status page lets you monitor worker status and load balancing statistics in real time.
<VirtualHost *:80>
ServerName admin.example.com
# mod_jk status page
<Location /jkstatus>
JkMount jkstatus
Require ip 127.0.0.1 192.168.1.0/24
</Location>
</VirtualHost>
Add the status worker to workers.properties:
worker.list=worker1,jkstatus
worker.jkstatus.type=status
worker.jkstatus.read_only=true # Read-only (for security)
# Access status page (internal network only)
curl http://localhost/jkstatus/
Migrating from mod_jk to mod_proxy_http
Step-by-step guide for transitioning from legacy mod_jk to mod_proxy_http.
Step 1: Verify Tomcat HTTP Connector
<!-- server.xml — Confirm HTTP connector is present -->
<Connector port="8080" protocol="HTTP/1.1"
address="127.0.0.1"
connectionTimeout="20000"/>
Step 2: Update Apache Configuration
# Old mod_jk approach (remove)
# JkMount /* worker1
# New mod_proxy_http approach
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
# Exclude static files
ProxyPass /static !
ProxyPass /images !
# Forward dynamic requests
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
Step 3: Disable AJP Connector (Security)
<!-- server.xml — Comment out AJP connector -->
<!--
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"/>
-->
Troubleshooting
# Check mod_jk log
tail -f /var/log/apache2/mod_jk.log
# Common errors
# [warn] ajp_get_reply::jk_ajp_common.c: Timeout waiting for a reply
# Check worker status via CLI
# curl -s "http://localhost/jkstatus/?cmd=show&w=worker1"
# Check AJP port
ss -tlnp | grep 8009
# Temporarily increase log level for debugging
# JkLogLevel debug (change in httpd.conf then reload)
Summary
| Item | Location | Content |
|---|---|---|
| Module load | httpd.conf | LoadModule jk_module ... |
| Worker definition | workers.properties | ajp13 type, host, port |
| URL mapping | VirtualHost | JkMount /* worker1 |
| Static exclusion | VirtualHost | JkUnMount /static/* worker1 |
| Sticky sessions | workers.properties + server.xml | jvmRoute + sticky_session=true |
| Migration | — | Migrate to mod_proxy_http |