Skip to main content
Advertisement

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

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
AttributeDescription
connectiontimeoutConnection establishment wait time (seconds)
timeoutResponse wait time (seconds)
retryRetry interval after error (seconds), 0 = immediate
acquireConnection pool wait time (ms)
maxMaximum number of connections
ttlMaximum 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

ItemConfiguration
Required modulesproxy + proxy_http
Basic directivesProxyPass + ProxyPassReverse
Real IP forwardingRequestHeader set X-Forwarded-For/Proto
Exclude static filesProxyPass /static !
Load balancingproxy_balancer + stickysession=JSESSIONID
Cookie pathProxyPassReverseCookiePath
TimeoutProxyTimeout + connectiontimeout=10 timeout=60
Advertisement