Apache mod_proxy_balancer Load Balancing
Apache HTTPD provides powerful load balancing through the mod_proxy_balancer module. Define upstream groups with the balancer:// scheme and distribute requests using various algorithms (lbmethod).
Enabling Required Modulesβ
The following modules must be enabled for load balancing in Apache.
# Ubuntu/Debian
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests # Round Robin
sudo a2enmod lbmethod_bytraffic # Traffic-based
sudo a2enmod lbmethod_bybusyness # Least connections
sudo a2enmod slotmem_shm # Shared memory (required for balancer)
sudo systemctl restart apache2
# CentOS/RHEL (uncomment in httpd.conf)
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
Basic Load Balancer Configurationβ
Simplest Setup (byrequests)β
# /etc/apache2/sites-available/load-balancer.conf
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
# Define upstream group
<Proxy "balancer://mycluster">
BalancerMember "http://10.0.0.1:8080"
BalancerMember "http://10.0.0.2:8080"
BalancerMember "http://10.0.0.3:8080"
ProxySet lbmethod=byrequests # Round Robin
</Proxy>
# Forward all requests to the load balancer
ProxyPass "/" "balancer://mycluster/"
ProxyPassReverse "/" "balancer://mycluster/"
</VirtualHost>
lbmethod Algorithmsβ
byrequests (Request Count Based, Round Robin)β
Distributes based on the number of requests processed by each server, weighted by loadfactor. Behaves like Round Robin by default.
<Proxy "balancer://mycluster">
BalancerMember "http://10.0.0.1:8080" loadfactor=3
BalancerMember "http://10.0.0.2:8080" loadfactor=1
ProxySet lbmethod=byrequests
</Proxy>
loadfactor works like Nginx's weight. App1 handles 75%, App2 handles 25%.
bytraffic (Traffic Byte Based)β
Distributes based on processed traffic (bytes). Useful when response sizes vary widely, like file downloads.
<Proxy "balancer://mycluster">
BalancerMember "http://10.0.0.1:8080"
BalancerMember "http://10.0.0.2:8080"
ProxySet lbmethod=bytraffic
</Proxy>
When 100MB file downloads and 1KB API responses are mixed, byrequests simply counts requests, while bytraffic accounts for actual data processed. Best for image/video serving servers.
bybusyness (Minimum Active Requests)β
Routes to the server with the fewest currently active requests. Similar to Nginx's least_conn.
<Proxy "balancer://mycluster">
BalancerMember "http://10.0.0.1:8080"
BalancerMember "http://10.0.0.2:8080"
BalancerMember "http://10.0.0.3:8080"
ProxySet lbmethod=bybusyness
</Proxy>
Best for API servers or backends with heavy DB queries.
Complete BalancerMember Parameter Referenceβ
<Proxy "balancer://mycluster">
BalancerMember "http://10.0.0.1:8080"
loadfactor=3 # Weight (default: 1)
retry=60 # Retry interval after failure (seconds), 0 = permanent exclusion
timeout=30 # Connection timeout (seconds)
acquire=3000 # Max connection wait time (ms)
max=100 # Max concurrent connections
ttl=60 # Idle connection lifetime (seconds)
route=jvm1 # JVM route ID for mod_jk integration
status=+H # Force status (+H=Hot Standby, +D=Disabled, +S=Stop, +I=Ignore errors)
BalancerMember "http://10.0.0.2:8080" loadfactor=1 status=+H
# +H: Hot Standby β only used when all other servers are down
ProxySet lbmethod=bybusyness
ProxySet stickysession=JSESSIONID # Session affinity
</Proxy>
Status Flag Referenceβ
| Flag | Meaning | When to Use |
|---|---|---|
+D | Disabled | Block traffic during maintenance |
+H | Hot Standby | Standby server (unused in normal operation) |
+S | Stopped | Block new connections, keep existing ones |
+I | Ignore errors | Ignore errors (exclude from health checks) |
-D | Remove flag | Re-enable |
Sticky Sessionβ
Configure so the same user always connects to the same server for session-based applications.
Cookie-based Sticky Session (Recommended)β
<Proxy "balancer://mycluster">
BalancerMember "http://10.0.0.1:8080" route=server1
BalancerMember "http://10.0.0.2:8080" route=server2
BalancerMember "http://10.0.0.3:8080" route=server3
ProxySet lbmethod=byrequests
ProxySet stickysession=JSESSIONID # Tomcat's default session cookie name
</Proxy>
Set jvmRoute in Tomcat's server.xml:
<!-- server.xml -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="server1">
Tomcat then appends .server1 to session IDs:
Set-Cookie: JSESSIONID=ABC123.server1; Path=/
Apache reads this cookie and routes to the server with route=server1.
Balancer Manager (Web Management Interface)β
Apache provides a management page to monitor load balancer status and change settings in real time from a browser.
<Location "/balancer-manager">
SetHandler balancer-manager
Require ip 127.0.0.1 10.0.0.0/8 # Allow internal network only
</Location>
# Enable and reload
sudo a2enconf balancer-manager
sudo systemctl reload apache2
# Access
curl http://localhost/balancer-manager
What you can do from the management page:
- View status, request count, and error count for each server
- Disable/enable servers (during maintenance)
- Change weights (loadfactor) in real time
- Reset session data
Production Configuration: Complete Load Balancer Setupβ
# /etc/apache2/sites-available/production-lb.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
ProxyRequests Off
ProxyPreserveHost On
# Main app cluster
<Proxy "balancer://appcluster">
BalancerMember "http://10.0.0.1:8080" loadfactor=3 retry=5 route=jvm1
BalancerMember "http://10.0.0.2:8080" loadfactor=3 retry=5 route=jvm2
BalancerMember "http://10.0.0.3:8080" loadfactor=1 retry=5 route=jvm3 status=+H
ProxySet lbmethod=bybusyness
ProxySet stickysession=JSESSIONID
ProxySet nofailover=Off
</Proxy>
# Static file cluster
<Proxy "balancer://staticcluster">
BalancerMember "http://10.0.1.1:80" loadfactor=1
BalancerMember "http://10.0.1.2:80" loadfactor=1
ProxySet lbmethod=byrequests
</Proxy>
# Static files: dedicated cluster
ProxyPass "/static/" "balancer://staticcluster/static/"
ProxyPassReverse "/static/" "balancer://staticcluster/static/"
# Admin page: single server (exclude from load balancing)
ProxyPass "/admin/" "http://10.0.0.1:8080/admin/"
ProxyPassReverse "/admin/" "http://10.0.0.1:8080/admin/"
# All other requests: app cluster
ProxyPass "/" "balancer://appcluster/"
ProxyPassReverse "/" "balancer://appcluster/"
ProxyTimeout 60
# Balancer Manager (internal access only)
<Location "/balancer-manager">
SetHandler balancer-manager
Require ip 127.0.0.1 10.0.0.0/8
</Location>
CustomLog /var/log/apache2/lb-access.log combined
ErrorLog /var/log/apache2/lb-error.log
</VirtualHost>
Algorithm Selection Guideβ
| Situation | Recommended lbmethod |
|---|---|
| Simple even distribution, identical specs | byrequests |
| File downloads, media streaming | bytraffic |
| API servers, variable processing times | bybusyness |
| Existing app without session sharing | byrequests + stickysession |
The next page covers AJP-based load balancing with mod_jk.