Aleks
Aleks

Reputation: 5854

Socket.io with nginx

I'm trying to serve static files by nginx 1.6 and to proxy socket traffic coming from Node.js web server with socket.io .

This is the relevant part of nginx.conf:

location /socket.io/ {
            proxy_pass http://localhost:3000;       
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
        }

It works perfectly directly between the browser and Node.js, but socket.io takes too long when proxied with nginx 1.6. A handshaking protocol takes too much time, but if left uninterrupted it eventually starts to work after a couple of minutes.

Static files delivery by nginx works perfectly.

What could be the problem?

UPDATE:

I analysed a bit the network traffic and determined that the following request lasts around a minute (it's exactly when the upgrade is requested):

Sec-WebSocket-Key: LhZ1frRdl+myuwyR/T03lQ==
Cookie: io=1-A7tpvwmoGbrSvTAAA5
Connection: keep-alive, Upgrade
Upgrade: websocket
....

The expected response is code 101 and:

Connection: upgrade
Sec-WebSocket-Accept: HXx3KKJadQYjDa11lpK5y1nENMM=
Upgrade: websocket
...

instead, the browser receives 400 and:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:8888
Connection: keep-alive
Content-Type: application/json
Server: nginx/1.6.2
Transfer-Encoding: chunked

UPDATE 2:

I determined that the same configuration works perfectly on my office computer, meaning that it's my home computer issue. Anyway, would be very nice to determine what exactly is going wrong.

Upvotes: 53

Views: 79322

Answers (7)

Nadeem Shah
Nadeem Shah

Reputation: 1

location / {
    proxy_pass http://localhost:3001;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

location /socket.io/ {
    proxy_pass http://localhost:3001/socket.io/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

Upvotes: 0

Naresh Kumar Gautam
Naresh Kumar Gautam

Reputation: 1

How to fix WebSocket is closed before the connection is established.

Answer in local my socket io connection was working fine but in production, it was not working, getting error WebSocket error

I fixed this by adding this config section in my Nginx conf

location ^~ /socket {
            proxy_pass http://localhost:3001;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
}

Upvotes: 0

Delcon
Delcon

Reputation: 2545

I you still have problems, like I did, here is what you need to do: align the 3 configurations. Let's say you want to communicate over "mysocket":

niginx:

  location /mysocket/ {
      proxy_pass http://localhost:3000; 
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection 'upgrade';
      proxy_set_header Host $host;
      proxy_cache_bypass $http_upgrade;
    }

nodejs:

const io = require('socket.io')(server, {
  path: '/mysocket'
});

client:

var io = require('socket.io-client');
const socket = io('http://myserver.com, {
    path: '/mysocket'
});

Upvotes: 30

Radu Toader
Radu Toader

Reputation: 1561

You might forgot about proxy_redirect off;

location / {
            proxy_pass http://localhost:3000/;
            include proxy_params;
            proxy_redirect off;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
    }

EDIT:

My source : https://www.nginx.com/blog/websocket-nginx/

The RFC states "Upgrade" https://www.rfc-editor.org/rfc/rfc6455#section-1.2

 ...
   The handshake from the client looks as follows:

    GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Origin: http://example.com
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13

The handshake from the server looks as follows:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    Sec-WebSocket-Protocol: chat
...

but also says :

   ....
   3.  If the response lacks a |Connection| header field or the
   |Connection| header field doesn't contain a token that is an
   ASCII case-insensitive match for the value "Upgrade", the client
   MUST _Fail the WebSocket Connection_.
   ....

So yes, every header should be Case insensitive, but there are servers like Microsoft IIS / or developer specific implementation which are not case insensitive.

It all depends on the underlying server after nginx, if it does accept case-insensitive or not.

Upvotes: -1

kuubson
kuubson

Reputation: 189

check it out! the most important part here are these 2 signs ^~ already lost 3 days until i managed to get nginx with socketio working..

location ^~ /socket {
            proxy_pass http://localhost:3001;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
}

Upvotes: 5

Paulo Henrique Martins
Paulo Henrique Martins

Reputation: 1490

In a running server, the nginx's configuration being used here is:

  # Requests for socket.io are passed on to Node on port 3000
  location ~* \.io {
      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 false;

      proxy_pass http://localhost:3000;
      proxy_redirect off;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

Upvotes: 131

Sam Bauers
Sam Bauers

Reputation: 413

Every example I have seen (Nginx docs, Nginx blog) uses:

proxy_set_header Connection "upgrade";

Note all lowercase "upgrade". Your example has a capital "U". Maybe worth trying.

Upvotes: 2

Related Questions