Linux – Error 404 when connecting to websocket behind nginx proxy_pass

linuxnginxproxypasswebsocket

I would like to serve up a websocket behind a location on my webserver. For example, if my domain is http://mydomain I would like my websocket to be available at ws://mydomain/ws.

I am running a local websocket server on port 8080, and I can connect to it using both localhost and the local network ip (192.168.1.100). When I try to access the websocket using this path, I get Error: Unexpected server response (404).

Here is my nginx config in an attempt to do this:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    listen [::]:80;

    access_log /var/log/nginx/mydomain.access.log;
    error_log /var/log/nginx/mydomain.error.log;

    server_name mydomain;

    location / {
        alias /var/www/mydomain/htdocs;
        index index.html;
        try_files $uri $uri/ =404;
    }

    location /ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://websocket;
    }
}

I've found several previous questions on the internet but none seem to address this issue; I'm not even sure if this type of proxy is possible.

I originally had a websocket protocol defined "chat" and I was getting a Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received error; removing it fixes it for now.

My websocket server is using a locally-built NetCoreServer from https://github.com/chronoxor/NetCoreServer and is nearly identical to the example unsecure websocket server example they have. Let me know if there's any additional information I can give that would help to resolve this issue.

Best Answer

Solution is to remove all not mandatory headers, remove upstream function and point all websockets endpoints, no the main server without endpoints. For me main server was ws.example.com and i have ws.example.com/chat and ws.example.com/notifications so i set it like this:

location /chat {
  proxy_pass "http://127.0.0.1:2020/chat/";
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
location /notifications
{                                                                                                                                                                                                                                                    
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_pass "http://127.0.0.1:2020/notifications/";
}  
location / { return 405;}

If you have used different endpoints for each service, upstream won't work, but i have no idea why.

I almost forgot. My $http_upgrade variable is mapped like this:

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
} 

In your case it will be caused of wrong $connection_upgrade you took it from SoF and i made same mistake:

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

        proxy_pass "http://127.0.0.1:8080/ws/";
    }