vi / websocat

Command-line client for WebSockets, like netcat (or curl) for ws:// with advanced socat-like functions
MIT License
6.72k stars 257 forks source link

WebsocketError: Received unexpected status code (200 OK) when proxying with nginx #181

Closed lidh15 closed 1 year ago

lidh15 commented 1 year ago

websocat returns status code https://github.com/vi/websocat/issues/55, but it is (200 OK) setup: start a grpc server at 50051, then

websocat --oneshot -b ws-l:127.0.0.1:1234 tcp:127.0.0.1:50051&
websocat --oneshot -b tcp-l:127.0.0.1:50050 ws://127.0.0.1:1234/&

by now grpcurl 127.0.0.1:50050 returned the expected results, but if I proxy it with nginx (version 1.20):

websocat --oneshot -b ws-l:127.0.0.1:1234 tcp:127.0.0.1:50051&
websocat --oneshot -b tcp-l:127.0.0.1:50050 ws://127.0.0.1:5678/&

nginx.conf (partial)

server {
    listen       33333;
    location / {
        proxy_pass http://127.0.0.1:1234;
    }
}
server {
    listen       5678;
    location / {
        proxy_pass http://127.0.0.1:33333;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

grpcurl 127.0.0.1:50050 will timed out and websocat reports "WebsocketError: Received unexpected status code (200 OK)"

lidh15 commented 1 year ago

by the way, it won't throw errors if I simply proxy 5678 to 1234:

server {
    listen       5678;
    location / {
        proxy_pass http://127.0.0.1:1234;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

but I do need a bridge server because in my real environment 1234 is not connectable to 5678.

lidh15 commented 1 year ago

Okay I figured it out, it is because nginx location is not working, all the requests went to root location. when doing websocat --oneshot -b tcp-l:127.0.0.1:50050 ws://127.0.0.1:5678/ this "ws://127.0.0.1:5678/" is not a prefix but exactly the url, as a result, only location / {} block worked in nginx.conf Am I getting something wrong from the demo usecase? It's common that a server has hundreds of endpoints, if every tcp-l listening to only one endpoint, the proxy will be unusable at all.

vi commented 1 year ago

It's common that a server has hundreds of endpoints, if every tcp-l listening to only one endpoint, the proxy will be unusable at all.

You should describe the use case in more detail. Typically Websocat (at least version 1) is designed to serve just one type of Websocket connection. Routing is out of scope for now (that's where nginx/caddy is currently needed).

If you proxy ws-l to tcp then URL is getting lost anyway. If you proxy to exec: then you can use --set-environment for WEBSOCAT_URI (but that may be not a recommended method).

Provide an example with multiple (not hundreds, just two or three) endpoints to make it clearer where the duplication occurs.

You can also connect Nginx and Websocat using UNIX sockets instead of TCP sockets. That may be more clear and won't waste the port numbers. It would still require multiple processes though.

If needed, packing multiple sessions of Websocat in one process does not look like too difficult feature to add.

lidh15 commented 1 year ago

It is a good suggestion that uses UNIX sockets instead of TCP sockets, I will try it.