Apache as a Secure Reverse Proxy
Apache as a Secure Reverse Proxy
Configure Apache for secure reverse proxy operations:
# Enable required modules
sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests headers rewrite ssl
# /etc/apache2/sites-available/secure-reverse-proxy.conf
<VirtualHost *:443>
ServerName example.com
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Hide backend information
Header unset X-Powered-By
Header unset Server
# Request filtering
<Location />
# Method restrictions
<LimitExcept GET POST PUT DELETE HEAD OPTIONS>
Require all denied
</LimitExcept>
# IP-based access control
<RequireAll>
Require all granted
# Block specific IPs
Require not ip 10.0.0.0/8
Require not ip 192.168.0.0/16
</RequireAll>
</Location>
# Proxy configuration
ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 10
# Backend server configuration with load balancing
<Proxy "balancer://backend_cluster">
BalancerMember http://backend1.internal:8080 route=backend1 connectiontimeout=5 timeout=30
BalancerMember http://backend2.internal:8080 route=backend2 connectiontimeout=5 timeout=30
BalancerMember http://backend3.internal:8080 route=backend3 status=+H
ProxySet stickysession=JSESSIONID|jsessionid
ProxySet lbmethod=byrequests
ProxySet failontimeout=On
</Proxy>
# Security filters for proxy
<Proxy *>
Require all granted
# Add security headers to proxied requests
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-For "%{X-Forwarded-For}e, %{REMOTE_ADDR}s"
</Proxy>
# Main proxy rules
ProxyPass / balancer://backend_cluster/
ProxyPassReverse / balancer://backend_cluster/
# WebSocket support
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://backend_cluster/$1" [P,L]
# Security rules for specific paths
<LocationMatch "^/admin">
Require ip 10.0.1.0/24
# Additional authentication
AuthType Basic
AuthName "Admin Access"
AuthUserFile /etc/apache2/.htpasswd_admin
Require valid-user
</LocationMatch>
# Rate limiting for login
<Location "/login">
SetEnvIf Request_URI "^/login" login_request
# Use mod_evasive for rate limiting
DOSHashTableSize 3097
DOSPageCount 5
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 300
</Location>
# Mod_security rules
<IfModule mod_security2.c>
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecRequestBodyLimit 10485760
SecRequestBodyNoFilesLimit 131072
# Custom rules for reverse proxy
SecRule REQUEST_HEADERS:Content-Type "!^(application/x-www-form-urlencoded|multipart/form-data|application/json|text/xml|application/xml)" \
"id:1001,phase:1,deny,status:415,msg:'Unsupported Media Type'"
SecRule REQUEST_URI "@contains .." \
"id:1002,phase:1,deny,status:400,msg:'Path Traversal Attack'"
</IfModule>
# Logging
ErrorLog ${APACHE_LOG_DIR}/reverse-proxy-error.log
CustomLog ${APACHE_LOG_DIR}/reverse-proxy-access.log combined
# Additional security directives
ServerSignature Off
ServerTokens Prod
TraceEnable Off
</VirtualHost>
# HTTP to HTTPS redirect
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>