17

I'm trying to configure Apache 2.4 for proxying the websocket connection for socket.io to a node.js websocket server, using mod_proxy_wstunnel. We had this working fine with socket.io 0.9, but with the 1.0 release they changed the socket endpoint to a query parameter, and now I'm having trouble configuring apache with the correct proxy instructions.

All requests to /socket.io/?EIO=N&transport=websocket (where N is any digit, usually 2) need to be forwarded to ws://localhost:8082/socket.io/, but all other requests need to be forwarded to http://localhost:8082/socket.io/.

I've tried variations of both of the following configs:

ProxyPass /socket.io/?EIO=2&transport=websocket http://localhost:8082/socket.io/?EIO=2&transport=websocket
ProxyPassReverse /socket.io/?EIO=2&transport=websocket http://localhost:8082/socket.io/?EIO=2&transport=websocket

ProxyPass /socket.io/ http://localhost:8082/socket.io/
ProxyPassReverse /socket.io/ http://localhost:8082/socket.io/

.

RewriteRule /socket.io/?EIO=([0-9]+)&transport=websocket ws://localhost:8082/socket.io/ [QSA,P]

ProxyPass /socket.io/ http://localhost:8082/socket.io/
ProxyPassReverse /socket.io/ http://localhost:8082/socket.io/

I've gathered from my googling that ProxyPass and Locations can't target query strings, so is there any other option here? The paths are hard-coded into socket.io, so short of forking the entire library I can't change them.

Twipped
  • 613
  • 2
  • 7
  • 10

1 Answers1

40

Use Rewrite conditions to match for this special case:

RewriteEngine On
RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
RewriteCond %{QUERY_STRING} transport=websocket    [NC]
RewriteRule /(.*)           ws://localhost:8082/$1 [P,L]

ProxyPass        /socket.io http://localhost:8082/socket.io
ProxyPassReverse /socket.io http://localhost:8082/socket.io

NOTE As Mark W noted below. These must be entered at vhost level and not at server or .htaccess level.

You can also reference a balancer:

<Proxy balancer://http-localhost/>
    BalancerMember http://localhost:8082 keepalive=On smax=1 connectiontimeout=10 retry=600 timeout=900 ttl=900
    BalancerMember http://localhost:8083 keepalive=On smax=1 connectiontimeout=10 retry=600 timeout=900 ttl=900
    ProxySet lbmethod=bytraffic
</Proxy>

<Proxy balancer://ws-localhost/>
    BalancerMember ws://localhost:8082 keepalive=On smax=1 connectiontimeout=10 retry=600 timeout=900 ttl=900
    BalancerMember ws://localhost:8083 keepalive=On smax=1 connectiontimeout=10 retry=600 timeout=900 ttl=900
    ProxySet lbmethod=bytraffic
</Proxy>

RewriteEngine On
RewriteCond %{REQUEST_URI}  ^/socket.io                [NC]
RewriteCond %{QUERY_STRING} transport=websocket        [NC]
RewriteRule /(.*)           balancer://ws-localhost/$1 [P,L]

ProxyPass        /socket.io balancer://http-localhost/socket.io
ProxyPassReverse /socket.io balancer://http-localhost/socket.io
Jaap
  • 103
  • 3
PeterPramb
  • 501
  • 3
  • 3
  • +100000 You made my day. Been at this for hours. I used the first code snippet. I don't need a balancer at the moment. – Eamorr Sep 07 '14 at 15:30
  • I'm not able to get this to work. Apache keeps responding with a 404 code. It shows up in the access log as if it's trying to load a normal file, and the socket node process shows no sign of receiving the request (it does show the call for the socket.io.js file) – Twipped Sep 22 '14 at 21:54
  • 1
    It appears that mod_rewrite doesn't know the ws:// protocol. I see this in my rewrite log: `forcing proxy-throughput with http://[REDACTED].dev/ws://localhost:8082/socket.io/` (domain.dev – Twipped Sep 22 '14 at 22:33
  • This is probably why: https://issues.apache.org/bugzilla/show_bug.cgi?id=55598 Looks like support for the protocol was added in Apache 2.5 – Twipped Sep 22 '14 at 22:35
  • Which version are you using? I'm using the rewrites above with 2.4.10 with no problems. – PeterPramb Sep 24 '14 at 21:35
  • This is definitely the right stuff and works even on 2.2-series with the mod_proxy websockets backport. Additional discussion https://github.com/Automattic/socket.io/issues/1696 – lkraav Dec 28 '14 at 09:01
  • 5
    **NOTE**: These blocks should be placed within the `` block in the exact order described, *even if you are using the document root* (e.g. `/var/www/html`). I spent nearly 2 hours trying to figure out why these changes were not working properly, only to find out that the `RewriteRule`'s were not functioning at the root level of `httpd.conf` (although `ProxyPass` was working). The `ProxyPass` directives do not work in `` blocks or `.htaccess` files (although the `RewriteRule`'s do), so the logical place to group these changes is in ``. – Jake Z Sep 09 '15 at 18:35
  • When using a load balancer like this I can no longer detect when clients pages are closed in a timely manner. If I connect directly I can tell instantly, if I go through a load balancer proxy like this it takes over a minute before I can tell they've closed their browser page. – kojow7 Mar 27 '18 at 02:56
  • @PeterPramb , please, could you help me out with https://stackoverflow.com/questions/70210654/httpd-websocket-error-upgrade-token-not-found-in-connection-header – gbenroscience Dec 03 '21 at 08:11