Nginx finally added the long awaited Websockets proxying functionality.
In this regard, I hasten to share configs and small details.
For those who did not know, earlier proxying was possible through a third-party module, with restrictions that did not suit many. Well, we are not talking about that.
Now on one port you can proxy http and ws traffic, moreover, for example, under one SSL certificate, and all this with
a familiar familiar syntax.
')
Ws are available starting from version 1.3.13, and just today they added support to the ngx_http_uwsgi_module and ngx_http_scgi_module modules for 1.3.14
This is what the documentation says about the mechanism used.
To convert the connection between the client and the server from HTTP / 1.1 to WebSocket, the protocol change mechanism available in HTTP / 1.1 is used.
But there is a difficulty: since “Upgrade” is a hop-by-hop header, it is not transferred from the client to the proxied server. For direct proxying, clients can use the CONNECT method to get around this problem. However, during reverse proxying, this approach does not work, because the client does not know anything about the proxy server, and special processing is required on the proxy server.
Starting with version 1.3.13, nginx has a special mode of operation that allows you to establish a tunnel between the client and the proxied server if the proxied server returned a response with code 101 (Switching Protocols), and the client asked to change the protocol using the “Upgrade” header in the request .
As noted above, hop-by-hop headers, including “Upgrade” and “Connection”, are not transmitted from the client to the proxied server, therefore, in order for the proxied server to know about the client’s intention to change the protocol to WebSocket, these headers should be sent explicitly :
Config
A simple example:
location /ws/ { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
A more complex example in which the value of the “Connection” field in the request header to the proxied server depends on the presence of the “Upgrade” field in the client request header:
http { map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { ... location /ws/ { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }
And a little non-obvious, but the important parameter is proxy_read_timeout, which is defaulted to 60s, after which the connection is terminated, which is usually not necessary for ws.
Therefore, we added:
http { ... proxy_read_timeout 950s; ... }
Most likely your application will need other timeout digits, so don't copy-paste mindlessly;)