Skip to content

How to make Socket.IO work behind nginx (mostly)

by Qard on September 21st, 2011

UPDATE: News from jpetazzo:

dotCloud now has beta websockets support, so this hack should no longer be necessary. Just point your custom domain to experimental-gateway-1.dotcloud.com instead of gateway.dotcloud.com and you will be using a websockets-aware load balancer instead of the default one running Nginx.

Most web hosts with node.js support host it behind an nginx proxy. Sadly, Socket.IO doesn’t work at all behind nginx without a bit of hacking. Currently there’s no vhost-supported way to run websockets through nginx, but we can at least get the xhr transport to work properly–basically everything can do xhr-polling.

Turns out that nginx doesn’t really like how Socket.IO uses the “Connection: keep-alive” header, so lets just remove that. All we need to do is overwrite a function in the xhr-polling transport. This should do it;

io.configure(function() {
  io.set("transports", ["xhr-polling"]);
  io.set("polling duration", 10);

  var path = require('path');
  var HTTPPolling = require(path.join(
    path.dirname(require.resolve('socket.io')),'lib', 'transports','http-polling')
  );
  var XHRPolling = require(path.join(
    path.dirname(require.resolve('socket.io')),'lib','transports','xhr-polling')
  );

  XHRPolling.prototype.doWrite = function(data) {
    HTTPPolling.prototype.doWrite.call(this);

    var headers = {
      'Content-Type': 'text/plain; charset=UTF-8',
      'Content-Length': (data && Buffer.byteLength(data)) || 0
    };

    if (this.req.headers.origin) {
      headers['Access-Control-Allow-Origin'] = '*';
      if (this.req.headers.cookie) {
        headers['Access-Control-Allow-Credentials'] = 'true';
      }
    }

    this.response.writeHead(200, headers);
    this.response.write(data);
    this.log.debug(this.name + ' writing', data);
  };
});
  • http://twitter.com/jyoungblood jonathan youngblood

    wow. i killed quite a bit of time trying to figure out why socket.io wasn’t working on my server…and now i know. thanks so much for posting this.

  • http://srirangan.net Srirangan

    Hmm.. the way I got Socket.io to work with Nginx at Review19 – http://review19.com – was to compile Nginx with the TCP Proxy module (https://github.com/yaoweibin/nginx_tcp_proxy_module). Didn’t require any modifications of the Socket.io code but I needed to declare an additional tcp {} block in nginx.conf

  • http://www.stephenbelanger.com Stephen Belanger

    Yep, I’ve seen that fix too. Unfortunately, it doesn’t work for vhosts. So cloud hosting services like dotcloud can’t use that.

  • http://srirangan.net Srirangan

    Umm .. it should work for vhosts if they have a dedicate IP. The problem was the clash of ports if both the tcp {} and http {} blocks were declared for all IPs.

  • http://www.stephenbelanger.com Stephen Belanger

    Most of the “auto-scaling” cloud host type services can’t give unique IPs though. Typically they are just a thin layer on top of AWS.

  • http://twitter.com/hosamebrahim hosam.ebrahim

    Can anyone please tell me exactly the file name I should update it,  I don’t know where to override this function?

  • http://www.stephenbelanger.com Stephen Belanger

    It goes wherever your Socket.IO code is defined. I like to put it right after io.attach().