Error 404 when connecting to websocket behind nginx proxy_pass

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.


Solution 1:

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/";
    }