title: nginx, node.js and socket.io - is there a working marriage?
body: <p><code>nginx</code> is a killer static file server.</p>
  
  <p>it can serve <code>node.js</code>, as in <a href="https://stackoverflow.com/questions/5009324/node-js-nginx-and-now">this example</a>, but in a limited fashion.</p>
  
  <p>but <code>nginx</code> is <a href="https://github.com/LearnBoost/socket.io/wiki/Nginx-and-Socket.io" rel="nofollow noreferrer">apparently unable</a> to proxy <code>websockets</code>.</p>
  
  <p>the only thing I found that might work is using <a href="http://haproxy.1wt.eu/" rel="nofollow noreferrer">HAProxy</a> front end as per <a href="http://jfarcand.wordpress.com/2011/10/06/configuring-haproxy-for-websocket/" rel="nofollow noreferrer">this article</a> - but it's from October 6, 2011.</p>
  
  <p>this <em>has</em> to be a common problem, but I'm not finding a very common solution.</p>
  
  <p><hr /></p>
  
  <h2>Solution</h2>
  
  <p>(see <a href="https://github.com/bangkok-maco/barebone-node" rel="nofollow noreferrer">https://github.com/bangkok-maco/barebone-node</a> for complete solution and details)</p>
  
  <p>ip testing schema:</p>
  
  <ul>
  <li>127.0.0.12 - www.chat.nit - public, in /etc/hosts and haproxy</li>
  <li>127.0.1.12 - internal nginx web server</li>
  <li>127.0.2.12 - internal chat serving node.js socket.io</li>
  </ul>
  
  <h3>/etc/haproxy/haproxy.cfg:</h3>
  
  <pre><code>global
   maxconn 4096
   nbproc 2
   daemon
   # user nobody
   log             127.0.0.1       local1 notice
  
  defaults
   mode http
  
  # listen on 127.0.0.12:80
  frontend app
   bind 127.0.0.12:80
   mode tcp
   timeout client 86400000
   default_backend www_backend
   acl is_chat hdr_dom(Host) chat
   acl is_websocket path_beg /socket.io
  
   use_backend chat_socket_backend if is_websocket is_chat
   tcp-request inspect-delay 500ms
   tcp-request content accept if HTTP
  
  # ngnix on 127.0.1.12:80
  backend www_backend
   balance roundrobin
   option forwardfor
   mode http
   option httplog
   option httpclose
   timeout server 30000
   timeout connect 4000
   server w1 127.0.1.12:80 weight 1 maxconn 1024 check
  
  # node (socket.io) on 127.0.2.12:80
  backend chat_socket_backend
   balance roundrobin
   mode http
   option httplog
   option forwardfor
   timeout queue 5000
   timeout server 86400000
   timeout connect 86400000
   timeout check 1s
   no option httpclose
   option http-server-close
   option forceclose
   server s14 127.0.2.12:8000 weight 1 maxconn 1024 check
  </code></pre>
  
  <h3>/etc/nginx/sites-enabled/www.chat.nit</h3>
  
  <pre><code>server {
      listen   127.0.1.12:80;
  
      root /data/node/chat;
      index client.html;
  
      server_name www.chat.nit;
  
      # favicon.ico is in /images
      location = /favicon.ico$ { rewrite /(.*) /images/$1 last; }
  
      # standard includes
      location ^~ /(css|images|scripts)/ {
              try_files $uri =404;
      }
  
      # html page (only in root dir)
      location ~ ^/([-_a-z]+).html$ {
              try_files $uri =404;
      }
  
      error_page 404 /404.html;
  
      # redirect server error pages to the static page /50x.html
      #
      error_page 500 502 503 504 /50x.html;
      location = /50x.html {
              root /usr/share/nginx/www;
      }
  }
  </code></pre>
  
  <h3>chat (node.js): server.js</h3>
  
  <pre><code>var app = require('http').createServer()
     , io = require('socket.io').listen(app);    
  app.listen(8000,'127.0.2.12');
  
  io.sockets.on('connection', function(socket) {
    ...
  };
  </code></pre>
  
  <h3>chat: client.html</h3>
  
  <pre><code>&lt;head&gt;
    &lt;script src="/scripts/socket.io/socket.io.js"&gt;&lt;/script&gt;
    &lt;script&gt;
      var socket = io.connect('http://www.chat.nit:80'); 
      ...
    &lt;/script&gt;
  &lt;/head&gt;
  </code></pre>
  
  <p>notes:</p>
  
  <ol>
  <li><p>link socket.io client js into <code>scripts/</code> directory</p>
  
  <p>/.../scripts$ ln -s ../node_modules/socket.io/node_modules/socket.io-client/dist/ socket.io</p></li>
  <li><p>/etc/default/haproxy (contrary to text, must set to work <em>at all</em>)</p>
  
  <p>ENABLED=1</p></li>
  <li><p>this version haproxy not logging.  found <a href="http://kevin.vanzonneveld.net/techblog/article/haproxy_logging/" rel="nofollow noreferrer">kvz's</a> write up on how to use <code>rsyslogd</code> via 127.0.0.1, but could not make it fly.</p></li>
  <li><p>this solution is <em>working</em> - not sysadmin quality to be sure.  (enhancements more than welcome.)</p></li>
  </ol>