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.
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.
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.
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With