Apache’s mod_proxy module turns Apache into a powerful reverse proxy and gateway, forwarding requests to backend application servers, other web servers, or balancer clusters. Unlike Nginx’s reverse proxy (which is native), Apache’s proxy functionality is modular: mod_proxy handles the core proxying, mod_proxy_http handles HTTP/1.1, mod_proxy_balancer provides load balancing, and mod_proxy_wstunnel handles WebSocket tunnelling. On RHEL 9, all these modules are included with the httpd package. This guide covers setting up a basic reverse proxy for a Node.js or Python app, SSL termination, load balancing with mod_proxy_balancer, WebSocket proxying, and passing the correct client IP headers to the backend.

Prerequisites

  • Apache installed and running on RHEL 9
  • A backend application on a local port (e.g., Node.js on port 3000)

Step 1 — Enable Required Modules

# Verify the proxy modules are loaded
httpd -M | grep proxy

# If not loaded, check the modules config
ls /etc/httpd/conf.modules.d/00-proxy.conf
cat /etc/httpd/conf.modules.d/00-proxy.conf

The following should be uncommented in 00-proxy.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 proxy_wstunnel_module modules/mod_proxy_wstunnel.so
apachectl configtest && systemctl reload httpd

Step 2 — Basic Reverse Proxy

vi /etc/httpd/conf.d/myapp.conf

    ServerName app.example.com

    # Disable forward proxy — only act as reverse proxy
    ProxyRequests Off
    ProxyPreserveHost On

    # Pass real client IP to backend
    RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e"
    RequestHeader set X-Forwarded-Proto "http"
    RequestHeader set X-Real-IP "%{REMOTE_ADDR}e"

    ProxyPass        / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    ErrorLog  /var/log/httpd/myapp.error_log
    CustomLog /var/log/httpd/myapp.access_log combined
# Allow Apache to connect to backends (SELinux)
setsebool -P httpd_can_network_connect 1

apachectl configtest && systemctl reload httpd

Step 3 — Load Balancing with mod_proxy_balancer


    ServerName app.example.com

    ProxyRequests Off
    ProxyPreserveHost On

    # Define the balancer cluster
    
        BalancerMember http://127.0.0.1:3000 loadfactor=1
        BalancerMember http://127.0.0.1:3001 loadfactor=1
        BalancerMember http://127.0.0.1:3002 loadfactor=1
        ProxySet lbmethod=byrequests
    

    ProxyPass        / balancer://myappcluster/
    ProxyPassReverse / balancer://myappcluster/

Step 4 — WebSocket Proxy with mod_proxy_wstunnel


    ServerName ws.example.com

    ProxyRequests Off

    # HTTP traffic
    ProxyPass        /api/ http://127.0.0.1:4000/api/
    ProxyPassReverse /api/ http://127.0.0.1:4000/api/

    # WebSocket traffic — must come before the HTTP rule
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /ws/(.*) ws://127.0.0.1:4000/ws/$1 [P,L]

    ProxyPass        /ws/ ws://127.0.0.1:4000/ws/
    ProxyPassReverse /ws/ ws://127.0.0.1:4000/ws/

Step 5 — Reverse Proxy with SSL Termination


    ServerName app.example.com
    Redirect permanent / https://app.example.com/



    ServerName app.example.com

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/app.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/app.example.com/privkey.pem

    ProxyRequests    Off
    ProxyPreserveHost On
    RequestHeader    set X-Forwarded-Proto "https"

    ProxyPass        / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

Verification Checklist

apachectl configtest
curl -I http://app.example.com
httpd -M | grep proxy
tail -f /var/log/httpd/myapp.error_log

Conclusion

Apache mod_proxy on RHEL 9 provides HTTP reverse proxying, load balancing across multiple backends, and WebSocket tunnelling. Combined with SSL termination and RequestHeader set X-Forwarded-Proto, your backend application receives accurate client information and the correct protocol signal.

Next steps: How to Enable HTTP/2 with Nginx on RHEL 9, How to Configure Nginx Load Balancing on RHEL 9, and How to Set Up Varnish Cache as a Reverse Proxy on RHEL 9.