WebSocket through SSL with Apache reverse proxy
Solution 1
I ended up solving this problem by using this configuration for the virtual host, which filters requests using the HTTP headers:
<VirtualHost *:443>
ServerName website.com
RewriteEngine On
# When Upgrade:websocket header is present, redirect to ws
# Using NC flag (case-insensitive) as some browsers will pass Websocket
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/ws/(.*) wss://localhost:8888/ws/$1 [P,L]
# All other requests go to http
ProxyPass "/" "http://localhost:8888/"
I'm leaving this as a reference in case it helps others
Solution 2
In order to place a secure reverse proxy server in front of an insecure websocket server, you could do this:
<VirtualHost *:443>
SSLEngine on
SSLProxyEngine on
SSLProtocol -all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2
SSLCipherSuite HIGH:aNULL:eNULL:EXPORT:DES:RC4:!MD5:!PSK:!SRP:!CAMELLIA
SSLCertificateFile /path/to/cert
SSLCertificateKeyFile /path/to/key
SSLCertificateChainFile /path/to/chain
ServerName website.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8888/$1 [P,L]
</VirtualHost>
This will take a request inbound for wss://website.com:443, and reverse proxy it to ws://localhost:8888.
If the websocket server is also secure, you can simply change ws://localhost:8888 to wss://website.com:8888
Solution 3
This is my setup of virtualhost that worked for me, I have .netcore app on docker with SignalR as a websocket service.
On 5000
my .netcore app is running, and on /chatHub
my signalR listens.
Will be helpful for future comers with same problem.
<IfModule mod_ssl.c>
<VirtualHost *:443>
RewriteEngine On
ProxyPreserveHost On
ProxyRequests Off
# allow for upgrading to websockets
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:5000/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:5000/$1 [P,L]
ProxyPass "/" "http://localhost:5000/"
ProxyPassReverse "/" "http://localhost:5000/"
ProxyPass "/chatHub" "ws://localhost:5000/chatHub"
ProxyPassReverse "/chatHub" "ws://localhost:5000/chatHub"
ServerName site.com
SSLCertificateFile /etc/letsencrypt/live/site.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/site.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Source: http://shyammakwana.me/server/websockets-with-apache-reverse-proxy-with-ssl.html
Related videos on Youtube
Andrei Savin
Updated on September 22, 2021Comments
-
Andrei Savin over 2 years
On the client side, I am trying to establish the wss connection:
var ws = new WebSocket("wss://wsserver.com/test")
and it returns an error:
WebSocket connection to 'wss://wsserver.com/test' failed: Error during WebSocket handshake: Unexpected response code: 400
The full headers are:
Request Headers
GET wss://wsserver.com/test HTTP/1.1 Host: wsserver.com Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: https://website.net Sec-WebSocket-Version: 13 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 Accept-Encoding: gzip, deflate, sdch, br Accept-Language: en-US,en;q=0.8 Sec-WebSocket-Key: Tj9AJ5TKglNf5LoHsQTpvQ== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Response Headers
Access-Control-Allow-Credentials:true Access-Control-Allow-Origin:https://website.net Connection:close Content-Length:18 Content-Type:text/plain; charset=utf-8 Date:Fri, 21 Apr 2017 21:03:45 GMT Server:Apache/2.4.18 (Ubuntu) Vary:Origin X-Content-Type-Options:nosniff
The server side is running on go at port 8888 behind an Apache reverse proxy. This is the Apache configuration:
<VirtualHost *:443> ServerName website.com ProxyPreserveHost On ProxyRequests Off ProxyPass "/" "wss://localhost:8888/"
mod_proxy and mod_proxy_wstunnel are installed.
Is there something missing here? It seems like the request goes through but no connection is established.
-
gre_gor about 7 years
lcalhost
? Is this a typo? -
Andrei Savin about 7 yearsyes, indeed, this was a typo, but it did not solve my problem
-
-
pimgeek almost 5 yearsIn my case it's a little bit tricky, Node-RED use /nodered/comms as EndPoint, so I have to change your rule to
RewriteRule ^/nodered/comms wss://localhost:1880/nodered/comms [P,L]
. -
nix over 4 yearsYou are missing parentheses around
/nodered/comms
. Without there won't be the matching group (a.k.a. back-reference) 1 available. See following link for details: httpd.apache.org/docs/2.4/rewrite/intro.html#regex -
Oleg over 2 yearsThanks, its works. Moreover, its works without port, just wss://domain.net