Skip to main content
Advertisement

Apache+Tomcat Integration Pro Tips

This chapter covers advanced know-how for diagnosing and resolving real-world problems in Apache+Tomcat integration environments. From leveraging the mod_jk status page to connection debugging, performance tuning, and incident response — everything you need for production operations.


Leveraging the mod_jk Status Page

The mod_jk jkstatus handler lets you monitor worker status and load balancing statistics in real time.

Configuration

# workers.properties — Add status worker
worker.list=worker1,jkstatus

worker.jkstatus.type=status
worker.jkstatus.read_only=true # Read-only is mandatory in production
# Apache VirtualHost — Status page path
<Location /jkstatus>
JkMount jkstatus
Require ip 127.0.0.1 10.0.0.0/8 # Internal network only
</Location>

Information Available on the Status Page

ItemDescription
StateOK / ERR (worker status)
ElectedTotal requests processed
ErrorsError count
SessionsCurrently active sessions
RouteSticky session routing key
LBFLoad balancing factor
# Check status via CLI
curl -s "http://localhost/jkstatus/?mime=prop" | grep worker

# Specific worker status
curl -s "http://localhost/jkstatus/?cmd=show&w=worker1"

# Enable/disable worker (only when read_only=false)
curl -s "http://localhost/jkstatus/?cmd=update&w=worker1&ac=0" # Disable
curl -s "http://localhost/jkstatus/?cmd=update&w=worker1&ac=1" # Enable

Integration Debugging — JkLogLevel

Increase JkLogLevel to analyze detailed logs.

# mod_jk log levels (by severity)
JkLogLevel debug # Most verbose (do NOT use in production — performance impact)
JkLogLevel info
JkLogLevel warn # Default recommended
JkLogLevel error
# Real-time log monitoring
tail -f /var/log/apache2/mod_jk.log

# Filter for errors
grep -i "error\|fail\|timeout" /var/log/apache2/mod_jk.log | tail -50

# Logs related to specific worker
grep "worker1" /var/log/apache2/mod_jk.log | tail -30

Common mod_jk Errors

Error MessageCauseResolution
Timeout waiting for a replyTomcat response delayIncrease socket_timeout, check Tomcat load
ajp_ilink_receive failedAJP connection droppedRestart Tomcat, check connection pool
No worker found for nameworkers.properties misconfigurationCheck worker.list and worker names
All workers are in error stateAll Tomcat instances downCheck Tomcat process and AJP port

mod_proxy_http Debugging

# Temporarily increase Apache log level
LogLevel proxy:debug proxy_http:debug
# Extract only mod_proxy related errors
grep -i "proxy\|ajp\|backend" /var/log/apache2/error.log | tail -50

# Check proxy connection status
curl -v http://localhost/ 2>&1 | grep -E "< HTTP|Connected|Request"

# Test backend (Tomcat) response directly
curl -v http://127.0.0.1:8080/ 2>&1 | head -30

Common mod_proxy Errors

HTTP CodeErrorCauseResolution
502 Bad GatewayNo backend responseTomcat down, port mismatchCheck Tomcat status, ss -tlnp | grep 8080
503 Service UnavailableConnection pool exhaustedRequest surgeIncrease max, check Tomcat threads
504 Gateway TimeoutResponse timeoutSlow query/processingIncrease timeout, analyze slow queries
500 Internal Server ErrorTomcat internal errorApplication exceptionCheck Tomcat catalina.out

Connection Pool Optimization

mod_jk workers.properties Tuning

# workers.properties — Connection pool optimization
worker.worker1.type=ajp13
worker.worker1.host=127.0.0.1
worker.worker1.port=8009

# Pool size = 75~80% of Tomcat maxThreads
worker.worker1.connection_pool_size=75

# Idle connection timeout: clean up long-unused connections
worker.worker1.connection_pool_timeout=600

# Socket timeout: max wait for Tomcat response
worker.worker1.socket_timeout=60

# TCP keepalive: enable if firewalls are dropping connections
worker.worker1.socket_keepalive=true

# Retry settings
worker.worker1.retries=2
worker.worker1.recovery_options=7

mod_proxy_http Connection Pool Tuning

# Global proxy connection settings
<IfModule mod_proxy.c>
# Limit total open connections
ProxyMaxForwards 10
</IfModule>

# Fine-grained control with ProxyPass attributes
ProxyPass / http://127.0.0.1:8080/ \
connectiontimeout=5 \ # Max 5 seconds to establish connection
timeout=60 \ # Max 60 seconds for response
retry=0 \ # Retry immediately on error (0=immediate)
acquire=3000 \ # Max 3 seconds waiting for connection pool
max=100 \ # Max 100 connections
ttl=300 # Max 300 seconds connection reuse

# Enable keepalive (maintain TCP connections to Tomcat)
SetEnv proxy-nokeepalive 0
SetEnv proxy-initial-not-pooled 0

Header Debugging

Verify that client IP and SSL information is correctly forwarded to Tomcat.

# Expose internal info in response headers for debugging (development only)
<VirtualHost *:443>
Header always set X-Debug-Remote-Addr "%{REMOTE_ADDR}s"
Header always set X-Debug-Forwarded-For "%{X-Forwarded-For}e"
Header always set X-Debug-Proto "%{X-Forwarded-Proto}e"
</VirtualHost>
# Check headers received by Tomcat (Spring Boot)
# application.properties
# logging.level.org.apache.tomcat=DEBUG

# Verify headers via curl
curl -I -H "X-Test: hello" https://example.com/

Sticky Session Troubleshooting

# Verify session created on Tomcat 1
curl -c cookies.txt https://example.com/login
cat cookies.txt
# JSESSIONID=abc123.tomcat1 ← .tomcat1 is the routing key

# Confirm next request routes to the same Tomcat
curl -b cookies.txt https://example.com/dashboard

Sticky Session Failure Checklist

1. Tomcat server.xml — Verify jvmRoute setting
<Engine jvmRoute="tomcat1">

2. workers.properties — Verify route setting
worker.tomcat1.route=tomcat1

3. Confirm JSESSIONID cookie contains .tomcat1 suffix

4. Verify sticky_session=true setting
worker.lb_worker.sticky_session=true

5. Session loss due to session expiry or Tomcat restart
→ sticky_session_force=false (allow fallback to other node)

Apache Configuration Validation Automation

# Check configuration syntax
sudo apache2ctl configtest

# Verify loaded modules
apache2ctl -M | grep -E "proxy|jk|headers|rewrite|ssl"

# List VirtualHosts
apache2ctl -S

# Trace actual request handling path (Apache 2.4)
# mod_remoteip trace

Proxy Request Logging

# Proxy request/response log format
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D" combined_timing

# Log slow requests exceeding 3000ms (3 seconds)
# (Use a custom log analysis script)

CustomLog ${APACHE_LOG_DIR}/access.log combined_timing
# Top 10 slowest requests (by processing time)
awk '{print $NF, $0}' /var/log/apache2/access.log | sort -rn | head -10

# Extract only 5xx error requests
grep ' 5[0-9][0-9] ' /var/log/apache2/access.log | tail -50

# Request count per hour
awk '{print $4}' /var/log/apache2/access.log | \
cut -d: -f2 | sort | uniq -c | sort -rn

Maintenance Mode (Graceful Maintenance)

# Maintenance page configuration
<VirtualHost *:443>
ServerName example.com

# Return 503 if maintenance flag file exists
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/maintenance.flag -f
RewriteCond %{REQUEST_URI} !=/maintenance.html
RewriteRule ^ /maintenance.html [R=503,L]

ErrorDocument 503 /maintenance.html
Alias /maintenance.html /var/www/maintenance.html
</VirtualHost>
# Start maintenance
touch /var/www/html/maintenance.flag

# End maintenance
rm /var/www/html/maintenance.flag

Security Hardening Checklist

# Hide server information
ServerTokens Prod # Expose only "Apache" (hide version)
ServerSignature Off # Remove server info from error pages

# Block unnecessary HTTP methods
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>

# Block directory browsing
<Directory />
Options -Indexes
AllowOverride None
</Directory>

# Slowloris defense
RequestReadTimeout header=20,MinRate=500 body=20,MinRate=500

Quick Reference: Diagnostic Commands

# 1. Check port status
ss -tlnp | grep -E "80|443|8080|8009"

# 2. Validate Apache configuration
sudo apache2ctl configtest && echo "OK"

# 3. Verify modules
apache2ctl -M | grep -E "proxy_http|proxy_ajp|jk"

# 4. Test Tomcat connection
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/

# 5. Test Apache → Tomcat proxy path
curl -s -o /dev/null -w "%{http_code}" http://localhost/

# 6. Check SSL certificate expiry
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -dates

# 7. Real-time error log monitoring
sudo tail -f /var/log/apache2/error.log

Summary

ItemTool/Method
mod_jk status monitoring/jkstatus handler + worker.jkstatus.type=status
Integration debuggingJkLogLevel debug / LogLevel proxy:debug
Connection pool tuningconnection_pool_size / max=100 ttl=300
Sticky session verificationJSESSIONID .tomcat1 suffix + jvmRoute
Configuration validationapache2ctl configtest + apache2ctl -M
Slow request analysis%D log format + awk script
Maintenance modemaintenance.flag file + RewriteCond
Security hardeningServerTokens Prod + RequestReadTimeout
Advertisement