Hi everyone,
I’m facing an issue with nginx as a reverse proxy. The client sends a POST request with Connection: keep-alive. The upstream backend (a custom HTTP service) responds with HTTP/1.1 200 OK and Connection: keep-alive (I verified this via tcpdump). However, nginx changes the response header to Connection: close before sending it back to the client, and then closes the TCP connection immediately.
This breaks connection reuse – the client has to establish a new TCP connection for every subsequent upload, which hurts performance and may break workflows that rely on a persistent connection.
Environment:
- nginx version: (please fill in your version, e.g. 1.24.0)
- OS: (e.g. Ubuntu 22.04, running inside Docker container)
- Backend: (e.g. custom HTTP server on 172.18.0.3:9006)
Observed behavior (from tcpdump):
- Client → nginx:
POST /file/upload HTTP/1.1withConnection: keep-alive - nginx → backend: same request, added
X-Real-IP, stillConnection: keep-alive - backend → nginx:
HTTP/1.1 200 OKwithConnection: keep-aliveandContent-Length - nginx → client:
HTTP/1.1 200 OKwithConnection: close(!!) and then sends FIN
Partial tcpdump log (annotated):
# Backend response to nginx (shows keep-alive)
20:46:24.019905 IP 172.18.0.3.9006 > 172.18.0.4.40422: Flags [P.], seq 46353:46492, ack 7390962, win 516, length 139
HTTP/1.1 200 OK
Content-Length:78
Connection: keep-alive
# nginx response to client (shows close)
20:46:24.019975 IP 172.18.0.4.9006 > 192.168.228.1.51015: Flags [P.], seq 199866:200061, ack 22151166, win 384, length 195
HTTP/1.1 200 OK
Server: nginx/1.29.8
Connection: close
nginx configuration (relevant part):
(Please paste your actual config, especially the location block that proxies to the backend. If you don’t want to share the full config, at least include these directives: proxy_pass, proxy_http_version, proxy_set_header Connection, keepalive_timeout, and any upstream block.)
Here is what I currently have (example – replace with yours):
location /file/upload {
proxy_pass http://backend_upstream;
proxy_http_version 1.1; # I have this set (or not?)
proxy_set_header Connection ""; # Not set currently
proxy_set_header X-Real-IP $remote_addr;
}
upstream backend_upstream {
server 172.18.0.3:9006;
keepalive 32;
}
What I have tried:
- Confirmed that the backend correctly returns
Connection: keep-alive - Checked that
keepalive_timeoutis not 0 (it’s 65) - Verified nginx version: (your version)
- I do NOT have
proxy_set_header Connection closeanywhere
Expected behavior:
nginx should preserve the upstream’s Connection: keep-alive (or at least not force close) so that the client can reuse the same TCP connection for multiple requests.
Questions:
- Why does nginx override the
Connectionheader from upstream? - What configuration changes are required to make nginx keep the connection alive to the client?
- Is there any implicit behavior (e.g.,
proxy_http_version 1.0default) that forces nginx to addConnection: closeeven when upstream uses 1.1?
Any help would be greatly appreciated. Thanks!