Why does nginx proxy_pass close my connection?
Asked Answered
B

2

23

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?

Brecher answered 16/10, 2017 at 13:21 Comment(0)
P
35

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 keepalive-upstream {
  server 127.0.0.1:1980;
  keepalive 64;
}

server { 
  location / { 
    proxy_pass http://keepalive-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.

Philately answered 16/10, 2017 at 13:58 Comment(6)
Is it possible to have upstream keepalive without an upstream block? I have a situation where we're dynamically assigning the proxy_pass value based upon a variable (e.g. proxy_pass https://$new_server:$new_port;.Bron
@Bron did you ever figure out an answer to your question? I am wondering the same?Pyroelectricity
What does the keepalive 64; do? is 64 the time to keep the connection alive?Twitch
@LibbyLebyane it's the "maximum number of idle keepalive connections to upstream servers", see nginx.org/en/docs/http/ngx_http_upstream_module.html#keepaliveSulfanilamide
Is upstream { ... } a syntactically valid directive? Must there not be a name between the word upstream and the opening bracket?Mythical
Despite what the docs say, shouldn't that line actually be proxy_set_header Connection "keep-alive"? Though HTTP/1.1 says keep-alive is the default behavior, popular clients such as browsers or Postman will send the "Connection: keep-alive" header regardless. I believe this is to avoid cases where the server doesn't adhere to spec and sends back "Connection: close" unless it receives an explicit "Connection: keep-alive" from the client, so would it hurt to do so here?Sima
S
10

keepalive should enable in upstream block, not direct proxy_pass http://ip:port.

For HTTP, the proxy_http_version directive should be set to “1.1” and the “Connection” header field should be cleared

like this:

upstream keepalive-upstream {
    server 127.0.0.1:1980;
    keepalive 23;
}

 location / {
    proxy_http_version 1.1;
    proxy_set_header Connection ""; 
    proxy_pass http://keepalive-upstream;
}
Spiculate answered 4/11, 2018 at 9:21 Comment(2)
Bear in mind that an upstream server may also elect to close the connection. This can happen when a 50x error is encountered. A packet capture can show you if this is the case.Pecuniary
Can proxy_http_version 1.1; and proxy_set_header Connection ""; be put in the http block and then apply to all contained location blocks, or do they have to be in each individual location block.Chemosh

© 2022 - 2024 — McMap. All rights reserved.