nginx_http_upstream_conf

Overview

upstream holds the backend information, how to select backend and free the peer connection based on balance algorithm.

explicit upstream defined in this way.

1
2
3
4
5
6
7
8
upstream up_1 {
ip_hash;
server 1.1.1.1:443 weight=1;
server 1.1.1.1:443 weight=2;
}
location /abc {
proxy_pass: https://up_1;
}

There is also another way to define an upstream called implicit upstream, for implicit upstream, there is no way to define balance algorithm(round robin is used) and set parameters for it.

1
2
3
location /abc {
proxy_pass: https://www.google.com/;
}

Http upstream

location may refer to an upstream by proxy_pass directive, that means at conf phase, we link the location to the upstream, later on when request matches that location, we select a server from the linked upstream, create a connection for the selected server, send request to it.

upstream conf

how server is selected

server selection depends on balance algorithm, nginx supports several algorithms

  • round robin
  • least connection
  • ip hash

each algorithm must provide peer.get and peer.free

  • peer.get(): select a server, update counter, its return value:
    • NGX_DONE: get a connected connection
    • NGX_OK: get a server, need to create new connection
    • NGX_BUSY: no server is available
  • peer.free(): free resource(free counter etc) used by peer.get.

what port is used when connecting upstream server

it depends how upstream is defined and used.

explicit upstream
we use port defined by server in upstream itself, if server has no port configured, for proxy_pass http:// use 80, for proxy_pass https:// use 443, never use port from url itself

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
http {
upstream ups {
server 1.1.1.1;
server 2.2.2.2:8000;
}
server {
listen 10.10.10.10;
location /a {
# 8080 is ignored
proxy_pass http://ups:8080;
}
}
server {
listen 10.10.10.10 ssl;
location /b {
# 8080 is ignored
proxy_pass https://ups:8080;
}
}
}

implicit upstream
we always use port from url itself, if no port in url, use 80 for http, 443 for https when connection with backend.

1
2
3
4
5
6
7
8
9
http {
server {
listen 10.10.10.10 ssl;
location / {
# proxy_pass https://www.google.com;
proxy_pass https://www.google.com:8443;
}
}
}

uri sent to upstream server

uri sent to upstream server depends on how proxy_pass is used.

case: proxy_pass without uri

1
2
3
4
5
6
7
8
# the request URI is passed to the server in the same form as by a client when the original request is processed

location /abc {
proxy_pass http://127.0.0.1;
}

$curl http://test.com/abcd/cool
# uri sent to upstream: /abcd/cool

case: proxy_pass has uri which uses variable

1
2
# we use uri from variable directly to replace original uri
proxy_pass http://127.0.0.1$request_uri;

case: proxy_pass with uri which is not variable

1
2
3
4
5
6
7
# the part of a normalized request URI matching the location is replaced by a URI specified in the directive

location /abc {
proxy_pass http://127.0.0.1/hot;
}
$curl http://test.com/abcd/cool
# uri sent to upstream: /hot/d/cool

details refer to ngx_http_proxy_create_request().