From 4cafd27e1315a0b48c0b323f585cb6fd3960dc47 Mon Sep 17 00:00:00 2001 From: Jason Stangroome <148754+jstangroome@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:58:21 +1100 Subject: [PATCH] Fix nginx websocket and keepalive support By default nginx will send a `Connection: close` request header to the upstream when proxying which breaks upstream connection keepalives and can introduce latency due to repeated upstream TCP handshakes, and port exhaustion under load due to accumulating `TIME_WAIT`/`CLOSE_WAIT` TCP sockets. To fix upstream keepalives we configure nginx to not send the `Connection` request header upstream by setting the value to blank. However, for websocket support, if the `Upgrade: websocket` request header is present, we must send a `Connection: upgrade` request header with it to the upstream. An nginx `map` allows us to support both within the same `location` block. --- docs/integration/nginx.md | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/docs/integration/nginx.md b/docs/integration/nginx.md index 2a9a1a3..561071e 100644 --- a/docs/integration/nginx.md +++ b/docs/integration/nginx.md @@ -32,6 +32,12 @@ upstream rustfs-console { server 127.0.0.1:9001; } +map $http_upgrade $proxy_set_header_connection { + # If the Upgrade request header is present, also send a `Connection: upgrade` request header upstream, + # otherwise prevent the default `Connection: close` request header being sent to preserve keepalives. + default "upgrade"; + "" ""; +} server { listen 80; @@ -59,14 +65,10 @@ server { proxy_connect_timeout 300; # Default is HTTP/1, keepalive is only enabled in HTTP/1.1 proxy_http_version 1.1; - proxy_set_header Connection ""; chunked_transfer_encoding off; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - - + proxy_set_header Connection $proxy_set_header_connection; proxy_pass http://rustfs; # This uses the upstream directive definition to load balance } @@ -99,14 +101,10 @@ server { proxy_connect_timeout 300; # Default is HTTP/1, keepalive is only enabled in HTTP/1.1 proxy_http_version 1.1; - proxy_set_header Connection ""; chunked_transfer_encoding off; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - - + proxy_set_header Connection $proxy_set_header_connection; proxy_pass http://rustfs-console; # This uses the upstream directive definition to load balance } @@ -149,6 +147,13 @@ Console: `www.rustfs.dev` ~~~ +map $http_upgrade $proxy_set_header_connection { + # If the Upgrade request header is present, send a `Connection: upgrade` request header upstream, + # otherwise prevent the default `Connection: close` request header being sent to preserve keepalives. + default "upgrade"; + "" ""; +} + server { listen 443; listen [::]:443; @@ -175,11 +180,10 @@ server { proxy_connect_timeout 300; # Default is HTTP/1, keepalive is only enabled in HTTP/1.1 proxy_http_version 1.1; - proxy_set_header Connection ""; chunked_transfer_encoding off; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; + proxy_set_header Connection $proxy_set_header_connection; proxy_pass http://127.0.0.1:9000; } @@ -195,12 +199,12 @@ server { proxy_connect_timeout 300; # Default is HTTP/1, keepalive is only enabled in HTTP/1.1 proxy_http_version 1.1; - proxy_set_header Connection ""; chunked_transfer_encoding off; proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; + proxy_set_header Connection $proxy_set_header_connection; + proxy_pass http://127.0.0.1:9001; } } -~~~ \ No newline at end of file +~~~