Why does nginx proxy_pass close my connection?

user34537 picture user34537 · Oct 16, 2017 · Viewed 19.4k times · Source

The documentation says the following

Sets the HTTP protocol version for proxying. By default, version 1.0 is used. Version 1.1 is recommended for use with keepalive connections and NTLM authentication.

In my nginx config I have

    location / {
        proxy_http_version 1.1;
        proxy_pass http://127.0.0.1:1980;
    }

Doing http://127.0.0.1:1980 directly I can see my app get many request (when I refresh) on one connection. This is the response I send

HTTP/1.1 200 OK\nContent-Type:text/html\nContent-Length: 14\nConnection: keep-alive\n\nHello World!

However nginx makes one request and closes it. WTH? I can see nginx sends the "Connection: keep-alive" header. I can see it added the server and date header. I tried adding proxy_set_header Connection "keep-alive"; but that didn't help.

How do I get nginx to not close the connection every thread?

Answer

Anatoly picture Anatoly · Oct 16, 2017

In order Nginx to keep connection alive, the following configuration is required:

  • Configure appropriate headers (HTTP 1.1 and Connection header does not contain "Close" value, the actual value doesn't matter, Keep-alive or just an empty value)

  • Use upstream block with keepalive instruction, just proxy_pass url won't work

  • Origin server should have keep-alive enabled

So the following Nginx configuration makes keepalive working for you:

upstream { 
  server 127.0.0.1:1980; 
  keepalive 64; 
}; 

server { 
  location / { 
    proxy_pass http://upstream; 
    proxy_set_header Connection ""; 
    proxy_http_version 1.1; 
  } 
}

Make sure, your origin server doesn't finalise the connection, according to RFC-793 Section 3.5:

A TCP connection may terminate in two ways: (1) the normal TCP close sequence using a FIN handshake, and (2) an "abort" in which one or more RST segments are sent and the connection state is immediately discarded. If a TCP connection is closed by the remote site, the local application MUST be informed whether it closed normally or was aborted.

A bit more details can be found in the other answer on Stackoverflow.