Proxying & Load Balancing¶
Once a location block decides a request isn't a static file, proxy_pass is how nginx hands it to
something else — and naming more than one "something else" is how nginx becomes a load balancer.
TL;DR — in 30 seconds:
- Inside a
locationblock,proxy_passforwards a matched request to a single target address. - Naming several servers inside an
upstreamblock turns that one target into a pool nginx picks from per request, instead of a single fixed address. - Without specifying an algorithm, nginx distributes requests across an
upstream's servers round-robin — the default behavior.
1. proxy_pass — forwarding to one upstream¶
Inside a location block, proxy_pass forwards the matched request to a single target address:
location /api/ {
proxy_pass http://app:8080;
}
Every request matching /api/ is now handled by whatever is listening at app:8080, not by nginx itself.
2. upstream — turning one target into a pool¶
Naming several servers inside an upstream block turns that single target into a pool nginx picks
from on each request:
upstream backend {
server app1:8080;
server app2:8080;
}
location /api/ {
proxy_pass http://backend;
}
proxy_pass now points at the upstream name instead of a single address — nginx decides, per request,
which server in the pool actually handles it.
flowchart LR
L["location /api/<br/>proxy_pass http://backend"] --> U["upstream backend"]
U -- "1st request" --> A1["app1:8080"]
U -- "2nd request" --> A2["app2:8080"]
U -- "3rd request" --> A1
3. Round-robin — the default behavior¶
Without specifying an algorithm, nginx distributes requests across an upstream's servers in turn —
round-robin — the default behavior for any upstream block. Other documented algorithms exist for
different needs (for example, routing by least active connections, or keeping a given client on the same
server) — reach for one of those only once round-robin's simple rotation stops being the right fit.
4. How this connects¶
- TLS termination (previous page) decrypts the connection first; what you've just read is what nginx does with the request after that — decide a target, then load-balance across it if more than one exists.
- The same "pool of targets behind one entry point" pattern reappears one layer out or one layer in once workloads move onto Kubernetes or a cloud provider — covered next, in nginx vs Ingress & cloud LB.
You can defend this when you can explain what changes about proxy_pass's behavior once you name more
than one server inside an upstream block, and state nginx's default behavior across that pool without
needing to look it up.