Ratchet + nginx + SSL/secure websocket

temuri picture temuri · Mar 19, 2014 · Viewed 9.2k times · Source

I've been trying to run Ratchet.io over SSL (this problem: php ratchet websocket SSL connect?).

My webserver is running at myhost.mobi, and I have created a separate virtual host for websocket service "wws.myhost.mobi".

My web socket:

$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0');
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            new Ratchet\Wamp\WampServer(
                $pusher
            )
        )
    ),
    $webSock
);

My nginx config (I'm on nginx 1.5.8):

upstream websocketserver {
        server localhost:8080;
}

server {
    server_name wss.myapp.mobi;

    listen 443;
    ssl on;
    ssl_certificate /etc/ssl/myapp-mobi-ssl.crt;
    ssl_certificate_key /etc/ssl/myapp-mobi.key;

    access_log /var/log/wss-access-ssl.log;
    error_log /var/log/wss-error-ssl.log;
    location / {
                proxy_pass http://websocketserver;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;

                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
                proxy_read_timeout 86400; # neccessary to avoid websocket timeout disconnect
                proxy_redirect off;
        }
}

My client-side script:

var conn = new ab.Session('wss://wss.myapp.mobi', function(o) {

    // ...

}, function() {
    console.warn('WebSocket connection closed');
}, {
    skipSubprotocolCheck: true
});

So, when I load the page in Firefox, I see an outgoing connection to wss://wss.myapp.mobi:8080/, which is hanging (the spinner) and never completes or dies. I do not see any trace of request arriving on the backend in the logs.

What am I missing there?

Thanks!

EDIT I have realized that I should be connecting to wss://wss.myapp.mobi, but now I am getting "101 Switching Protocols" status.

EDIT 2 Everything is working now with the config above. "101 Switching Protocols" status turns out to be a normal message. PROBLEM SOLVED!

Answer

Renjith Thankachan picture Renjith Thankachan · Jun 12, 2017

By checking question edit history, it is clear that, the configuration in the question was correct, temuri was trying to connect from client with port set in,

upstream websocketserver {
        server localhost:8080;
}

but this code block tells Nginx there is a tcp server running on port 8080, represents it as websocketserver alias, but the running server is not accessible to public.

Check the below configuration,

server {
    server_name wss.myapp.mobi;

    listen 443;
    ssl on;
    ssl_certificate /etc/ssl/myapp-mobi-ssl.crt;
    ssl_certificate_key /etc/ssl/myapp-mobi.key;

    access_log /var/log/wss-access-ssl.log;
    error_log /var/log/wss-error-ssl.log;
    location / {
                proxy_pass http://websocketserver;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;

                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
                proxy_read_timeout 86400; # neccessary to avoid websocket timeout disconnect
                proxy_redirect off;
        }
}

this configuration binds the domain wss.myapp.mobi to port 443 enabling ssl and proxying the requests to the local websocket server via proxy_pass directive, rest directives are for connection upgrades handling.

So the websocket server can be accessed from browser client with

// connect through binded domain
// instead of wss.myapp.mobi:8080 which will not work
var url = 'wss://wss.myapp.mobi';