Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebSocket through SSL with Apache reverse proxy

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.

like image 655
Andrei Savin Avatar asked Apr 21 '17 21:04

Andrei Savin


People also ask

Do WebSockets work through reverse proxy?

WebSocket over a Reverse Proxy. WebSocket communication can take place over any reverse proxy which is configured to perform forwarding at the transport layer. Some proxies are able to handle WebSocket communication from certain clients at the application layer.

Does Apache support WebSockets?

Apache server supports the module "mod_proxy_wstunnel" from the version 2.4. 10. This module requires the service of "mod_proxy". It provides support for the tunneling of web socket connections to a backend websockets server.

Can we use Apache as reverse proxy?

In addition to being a "basic" web server, and providing static and dynamic content to end-users, Apache httpd (as well as most other web servers) can also act as a reverse proxy server, also-known-as a "gateway" server.

Does WSS use SSL?

An SSL certificate is required for the WebSocket WSS (WebSocket Security) protocol to work in production environments that use the HTTPS protocol for the website. If your website uses an SSL certificate, you'll be required to use the WSS protocol for secure communications.


2 Answers

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

like image 133
Andrei Savin Avatar answered Oct 26 '22 10:10

Andrei Savin


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

like image 5
Big Sam Avatar answered Oct 26 '22 09:10

Big Sam