Configuring Apache2 as a Reverse Proxy for WebSocket Connections: Header Preservation and Protocol Upgrade Handling


2 views

When working with WebSocket connections behind Apache2, the main issue stems from how mod_proxy handles HTTP upgrade requests. By default, Apache2 treats WebSocket connections as regular HTTP requests, stripping crucial headers like Upgrade and Connection that are essential for WebSocket protocol negotiation.

You'll need to ensure these modules are enabled:


sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo a2enmod rewrite
sudo systemctl restart apache2

Method 1: Using ProxyPass with wss://

For secure WebSocket connections:


<VirtualHost *:443>
    ServerName yourdomain.com
    SSLEngine on
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem

    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule /(.*) ws://backend-server:8080/$1 [P,L]

    ProxyPass / ws://backend-server:8080/
    ProxyPassReverse / ws://backend-server:8080/

    ProxyPass /wss/ ws://backend-server:8080/
    ProxyPassReverse /wss/ ws://backend-server:8080/
</VirtualHost>

Method 2: Path-based WebSocket Routing

For applications where WebSocket endpoints are under specific paths:


<Location "/ws/">
    ProxyPass ws://backend-server:8080/ws/
    ProxyPassReverse ws://backend-server:8080/ws/
    ProxyPassReverseCookieDomain backend-server yourdomain.com
</Location>

After applying changes, test with these commands:


apachectl configtest
systemctl reload apache2
  • Connection drops after 60 seconds: Add ProxyTimeout 3600 to your config
  • Headers not being forwarded: Use ProxySet to preserve headers
  • Mixed content warnings: Ensure consistent http/https schemes

For complex setups requiring header manipulation:


<Location "/custom-ws/">
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set Origin "https://yourdomain.com"
    ProxyPass ws://backend-server:8080/custom-ws/
    ProxyPassReverse ws://backend-server:8080/custom-ws/
</Location>

When trying to proxy WebSocket connections through Apache2, many developers encounter a frustrating issue: Apache's mod_proxy treats WebSocket traffic as regular HTTP, stripping away essential headers like Upgrade and Connection. This breaks the WebSocket handshake protocol.

Ensure these modules are enabled:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo systemctl restart apache2

Here's a complete VirtualHost configuration for WebSocket proxying:

<VirtualHost *:80>
    ServerName yourdomain.com
    
    # WebSocket configuration
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule /(.*) "ws://backend-server:8080/$1" [P,L]
    
    # Regular HTTP proxy
    ProxyPass / http://backend-server:8080/
    ProxyPassReverse / http://backend-server:8080/
    
    # WebSocket-specific proxy
    ProxyPass /ws/ ws://backend-server:8080/ws/
    ProxyPassReverse /ws/ ws://backend-server:8080/ws/
</VirtualHost>
  • The ProxyPass directive with ws:// protocol is crucial for WebSocket support
  • Apache 2.4.47+ is recommended as it has improved WebSocket support
  • Timeout settings may need adjustment: ProxyTimeout 3600

If connections fail, check these common issues:

  1. Verify headers are being passed through with curl -v
  2. Check Apache error logs: tail -f /var/log/apache2/error.log
  3. Test backend WebSocket server directly to isolate the issue

For complex setups, consider:

# Using LocationMatch for specific paths
<LocationMatch "/ws/.+">
    ProxyPass ws://backend-server:8080/ws/
    ProxyPassReverse ws://backend-server:8080/ws/
</LocationMatch>

You might also want to add these headers for better compatibility:

# Add these inside your VirtualHost or Location directive
RequestHeader set Upgrade "websocket"
RequestHeader set Connection "Upgrade"