How to Use Apache for Reverse Proxy Load Balancing

How to use Apache for reverse proxy load balancing

How to use Apache for reverse proxy load balancing

Reverse proxy load balancing is the pattern I reach for whenever I need Apache to sit in front of one or more backend applications, hiding their internal structure entirely from the outside world. It’s a slightly different mental model than “traditional” load balancing, so in this post I want to walk through exactly how reverse proxying and load balancing combine in Apache, and how to configure it properly.

What Is Reverse Proxy Load Balancing?

A forward proxy sits in front of clients, making requests on their behalf. A reverse proxy sits in front of servers, receiving requests on their behalf and forwarding them to the appropriate backend. When you combine a reverse proxy with load balancing, Apache becomes the single entry point for all incoming traffic, deciding which backend server should actually handle each request.

From the client’s perspective, there’s only ever one server: Apache. The backend servers, their number, and their individual health are completely invisible.

Why Use Apache as a Reverse Proxy Load Balancer

Prerequisites

Step 1: Enable Required Modules

sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests headers
sudo systemctl restart apache2

Step 2: Basic Reverse Proxy (Single Backend)

Before adding load balancing, here’s the simplest reverse proxy configuration — useful to confirm the fundamentals work:

<VirtualHost *:80>
    ServerName example.com
    ProxyPreserveHost On
    ProxyPass "/" "http://192.168.1.10:8080/"
    ProxyPassReverse "/" "http://192.168.1.10:8080/"
</VirtualHost>

Step 3: Convert to Reverse Proxy Load Balancing

Now replace the single backend with a balancer pool:

<Proxy "balancer://webcluster">
    BalancerMember "http://192.168.1.10:8080"
    BalancerMember "http://192.168.1.11:8080"
    BalancerMember "http://192.168.1.12:8080"
    ProxySet lbmethod=byrequests
</Proxy>

<VirtualHost *:80>
    ServerName example.com
    ProxyPreserveHost On
    ProxyPass "/" "balancer://webcluster/"
    ProxyPassReverse "/" "balancer://webcluster/"
</VirtualHost>

Step 4: Preserve Important Headers

Backends often need to know details about the original request that get lost through proxying. I always set these headers explicitly:

RequestHeader set X-Forwarded-Proto "http"
ProxyPass "/" "balancer://webcluster/"
ProxyPassReverse "/" "balancer://webcluster/"
ProxyAddHeaders On

ProxyAddHeaders On ensures Apache automatically adds X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Server headers, which your backend application can use to reconstruct the original client’s request context.

Step 5: Add SSL Termination

For production, terminate SSL at Apache and proxy plain HTTP internally:

<VirtualHost *:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key

    RequestHeader set X-Forwarded-Proto "https"
    ProxyPreserveHost On
    ProxyPass "/" "balancer://webcluster/"
    ProxyPassReverse "/" "balancer://webcluster/"
</VirtualHost>

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

This way, clients always connect over HTTPS, while backend servers don’t need their own SSL certificates at all.

Step 6: Proxy Specific Paths to Different Backends

Reverse proxy load balancing doesn’t have to be all-or-nothing. I frequently route different URL paths to entirely different balancer pools — useful for microservices architectures:

<Proxy "balancer://api-cluster">
    BalancerMember "http://192.168.1.20:5000"
    BalancerMember "http://192.168.1.21:5000"
</Proxy>

<Proxy "balancer://web-cluster">
    BalancerMember "http://192.168.1.10:8080"
    BalancerMember "http://192.168.1.11:8080"
</Proxy>

ProxyPass "/api/" "balancer://api-cluster/"
ProxyPassReverse "/api/" "balancer://api-cluster/"

ProxyPass "/" "balancer://web-cluster/"
ProxyPassReverse "/" "balancer://web-cluster/"

Order matters here — more specific paths (/api/) must be defined before the catch-all (/).

Real-World Use Cases

Troubleshooting Common Issues

Redirects Point to Internal Backend URLs — this happens when ProxyPassReverse isn’t configured correctly, or the backend application generates absolute URLs using its internal hostname. Fix with ProxyPassReverse matched exactly to your ProxyPass, and consider mod_substitute for stubborn cases.

Backend Sees Apache’s IP Instead of the Real Client IP — ensure mod_remoteip or proper X-Forwarded-For handling is configured on the backend application to read the real client IP from headers rather than the raw socket connection.

Mixed Content Warnings After Adding SSL — confirm X-Forwarded-Proto is being set and that your backend application respects it when generating URLs, rather than hardcoding http://.

Security Best Practices

TraceEnable off

Performance Optimization Tips

FAQs

Is reverse proxy load balancing the same as a CDN? No. A CDN caches and serves content from geographically distributed edge locations; a reverse proxy load balancer distributes traffic across your own backend servers, typically within the same data center or region. They’re complementary and often used together.

Can I use Apache as a reverse proxy for non-HTTP protocols? Yes, with the right modules — mod_proxy_wstunnel for WebSockets, mod_proxy_ajp for AJP-based backends like Tomcat, and others depending on your protocol needs.

Does reverse proxy load balancing add significant latency? In most setups, the added latency is negligible compared to backend processing time, especially when Apache and the backend servers are on the same local network.

Summary and Key Takeaways

Using Apache for reverse proxy load balancing gives you a single, unified entry point for your application while completely abstracting away backend server details from clients. The combination of mod_proxy, mod_proxy_balancer, proper header forwarding, and SSL termination at the proxy layer covers the vast majority of production use cases — and path-based routing lets you extend the same pattern to microservices architectures without much additional complexity.

References

Exit mobile version