1

I am working on a node.js application using express to serve content and socket.io for websocket communication. The setup has been working fine, but now I want to be able to access the websocket via SSL, too. I thought using nginx (which we already used for other stuff) as a proxy was a good idea, and configured it like this:

upstream nodejs {
    server 127.0.0.1:8080;
}

server {
    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    server_name _;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass http://nodejs;
        proxy_redirect off;
    }
}

The node.js server is set up like this:

var express = require('express'),
    app = express();
// some app configuration that I don't think matters
server = http.createServer(app).listen(8080);
var io = require('socket.io').listen(server);
io.configure(function() {
    io.set('match original protocol', true);
    io.set('log level', 0);
    io.set('store', redisStore); // creation of redisStore not shown
}

Both nginx and node.js run inside a Vagrant box which forwards port 443 (which nginx listens on) to port 4443 on the host system.

With this setup, navigating to http://localhost:4443 (using Firefox 23) gives me access to the files served by Express, but when socket.io tries to connect to the socket, it throws the following error:

Blocked loading mixed active content "http://localhost:4443/socket.io/1/?t=1376058430540"

This outcome is sadly obvious, as it tries to load the JS file via HTTP from inside an HTTPS page, which Firefox does not allow. The question is why it does so in the first place.

Socket.io tries to determine which protocol is used to access the web page, and uses the same protocol in the construction of the above URL. In this case, it thinks it is being accessed over HTTP, which may be the result of being proxied. However, as I understand, setting match original protocol to true in the socket.io config is supposed to help in situations like this, but it does not in my case.

I have found numerous questions and answers here about websocket proxying, but none that deal with this particular issue. So I'm pretty much at wit's end, and would really appreciate some advice.

  • Is it an option to skip the proxy and set both https and http listeners in express, as I described in [this answer](http://stackoverflow.com/a/17709985/1380669)? – Plato Aug 09 '13 at 15:24
  • I tried doing that unsuccessfully once today, but I'll have a look at your answer and try again after the weekend. – Ulrich Schmidt-Goertz Aug 09 '13 at 15:46
  • Note that you will need to create the `options` argument with your SSL credentials to pass to the HTTPS listener. [Example here](http://stackoverflow.com/questions/18129819/https-url-with-port-number-not-working-on-ios/18130058#18130058) – Plato Aug 09 '13 at 15:48
  • No luck :( Your solution works just as well as my nginx setup, so I really don't need the proxy, but the error still occurs. So maybe the issue actually is the port forwarding done by Vagrant. I have opened a ticket on the socket.io github to ask the maintainers themselves for advice. Thank you nevertheless. – Ulrich Schmidt-Goertz Aug 12 '13 at 10:57
  • *facepalm* i think it is `match origin protocol` not `match original protocol` – Plato Aug 12 '13 at 14:06

1 Answers1

0

Change match original protocol to match origin protocol:

io.configure(function() {
    //io.set('match original protocol', true);
    io.set('match origin protocol', true);
    ...
}
Plato
  • 10,812
  • 2
  • 41
  • 61