mod_proxy_http Configuration — Modern Apache+Tomcat Integration
mod_proxy_http communicates with Tomcat using standard HTTP/1.1 and is the recommended method for new Apache+Tomcat integrations. It has no AJP vulnerabilities, configuration is straightforward, and you can leverage all standard Apache features including SSL termination, header control, and load balancing.
Enabling Modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod headers
sudo a2enmod rewrite
sudo systemctl reload apache2
apache2ctl -M | grep "proxy_http"
# proxy_http_module (shared)
Basic Configuration
# /etc/apache2/sites-available/myapp.conf
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off # Disable forward proxy
ProxyPreserveHost On # Preserve original Host header
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
Full Production Configuration
# /etc/apache2/sites-available/myapp-ssl.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# HTTPS redirect
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
# SSL configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
# Forward real client IP
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-For "%{X-Forwarded-For}e env=HTTP_X_FORWARDED_FOR"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s" env=!HTTP_X_FORWARDED_FOR
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
RequestHeader set X-Forwarded-Host "%{HTTP_HOST}s"
# Security headers
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Proxy settings
ProxyRequests Off
ProxyPreserveHost On
# Exclude static files
ProxyPass /static !
ProxyPass /favicon.ico !
ProxyPass /robots.txt !
# Dynamic requests → Tomcat
ProxyPass / http://127.0.0.1:8080/ connectiontimeout=10 timeout=60
ProxyPassReverse / http://127.0.0.1:8080/
# Static files served directly
Alias /static /var/www/myapp/static
<Directory "/var/www/myapp/static">
Options -Indexes
AllowOverride None
Require all granted
</Directory>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
</IfModule>
# Logs
CustomLog ${APACHE_LOG_DIR}/myapp_access.log combined
ErrorLog ${APACHE_LOG_DIR}/myapp_error.log
</VirtualHost>
ProxyPass Path Handling
Understanding the path transformation rules of ProxyPass is important.
# Pass path as-is
ProxyPass /app/ http://127.0.0.1:8080/app/
# /app/users → http://127.0.0.1:8080/app/users
# Transform path (watch trailing slashes)
ProxyPass /app/ http://127.0.0.1:8080/
# /app/users → http://127.0.0.1:8080/users
# API path branching
ProxyPass /api/v1/ http://127.0.0.1:8080/api/
# /api/v1/users → http://127.0.0.1:8080/api/users
ProxyPass ordering: Write more specific paths first.
# Correct order (specific paths first)
ProxyPass /api/admin http://127.0.0.1:8081/admin
ProxyPass /api/ http://127.0.0.1:8080/api/
ProxyPass / http://127.0.0.1:8080/
# Wrong order (/ catches all requests)
ProxyPass / http://127.0.0.1:8080/ # Do not place first
ProxyPass /api/ http://127.0.0.1:8080/api/ # Unreachable
Cookie Path Rewriting (ProxyPassReverseCookiePath)
Used when Tomcat sets a cookie path of /myapp/ that needs to be converted to /.
# When Tomcat sets Set-Cookie: Path=/myapp/
# Client accesses via Apache at /, causing a mismatch
ProxyPassReverseCookiePath /myapp/ /
ProxyPassReverseCookieDomain 127.0.0.1 example.com
Timeout and Retry Configuration
# Global proxy timeout
ProxyTimeout 60
# Per-ProxyPass attributes
ProxyPass / http://127.0.0.1:8080/ \
connectiontimeout=10 \
timeout=60 \
retry=5 \
acquire=3000 \
max=100 \
ttl=300
# Keepalive connection reuse
SetEnv proxy-nokeepalive 0 # Enable keepalive
SetEnv proxy-initial-not-pooled 0 # Use connection pool
| Attribute | Description |
|---|---|
connectiontimeout | Connection establishment wait time (seconds) |
timeout | Response wait time (seconds) |
retry | Retry interval after error (seconds), 0 = immediate |
acquire | Connection pool wait time (ms) |
max | Maximum number of connections |
ttl | Maximum connection reuse time (seconds) |
Load Balancing
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
sudo a2enmod lbmethod_bybusyness
<Proxy "balancer://tomcatcluster">
# Add members
BalancerMember "http://127.0.0.1:8080" route=tomcat1 loadfactor=1
BalancerMember "http://192.168.1.11:8080" route=tomcat2 loadfactor=1
# Backup server (when all main servers are down)
BalancerMember "http://192.168.1.12:8080" status=+H
# Load balancing settings
ProxySet lbmethod=bybusyness # bybusyness: prefer least busy server
ProxySet stickysession=JSESSIONID # Sticky sessions
ProxySet nofailover=Off # Allow failover to other servers
</Proxy>
ProxyPass / balancer://tomcatcluster/
ProxyPassReverse / balancer://tomcatcluster/
# Balancer management page
<Location /balancer-manager>
SetHandler balancer-manager
Require ip 127.0.0.1 10.0.0.0/8
</Location>
Health Check Configuration
# Apache 2.4.55+ built-in health check
<Proxy "balancer://tomcatcluster">
BalancerMember "http://127.0.0.1:8080" hcmethod=GET hcuri=/actuator/health hcinterval=10
BalancerMember "http://192.168.1.11:8080" hcmethod=GET hcuri=/actuator/health hcinterval=10
ProxySet lbmethod=byrequests
</Proxy>
Summary
| Item | Configuration |
|---|---|
| Required modules | proxy + proxy_http |
| Basic directives | ProxyPass + ProxyPassReverse |
| Real IP forwarding | RequestHeader set X-Forwarded-For/Proto |
| Exclude static files | ProxyPass /static ! |
| Load balancing | proxy_balancer + stickysession=JSESSIONID |
| Cookie path | ProxyPassReverseCookiePath |
| Timeout | ProxyTimeout + connectiontimeout=10 timeout=60 |