Defining an Upstream Pool
An upstream block groups a named pool of backend servers that nginx can load balance across; each server line can carry parameters like weight, max_fails, and fail_timeout that control passive health checking. By default, if a server fails to respond (connection refused, timeout, or a configured error status) max_fails times within fail_timeout seconds, nginx marks that server unavailable for the remainder of fail_timeout and stops sending it new requests, retrying it automatically once that window elapses.
Cricket analogy: It's like a captain benching a bowler who's been hit for three consecutive boundaries within one over, resting them for a set number of overs before trying them again later in the innings.
Passive vs Active Health Checks
Passive checks only detect a bad server after it has already failed a live client request, which means at least one real user experiences an error. Open-source nginx doesn't ship built-in active health checks, but nginx Plus adds a health_check directive that proactively probes each upstream server on a schedule with configurable URI, expected status, and body match, marking servers down before any client traffic ever reaches them; open-source deployments commonly replicate this by running an external health-checking service or the third-party nginx_upstream_check_module.
Cricket analogy: Passive checks are like only realizing a pitch has a dangerous crack when a batter gets hurt; active checks are like a groundsman inspecting the pitch every morning before play so the danger is caught before anyone bats on it.
Backup Servers and Manual Downtime
upstream api_pool {
server 10.0.1.10:9000 max_fails=3 fail_timeout=30s;
server 10.0.1.11:9000 max_fails=3 fail_timeout=30s;
server 10.0.1.12:9000 backup;
server 10.0.1.13:9000 down;
keepalive 32;
}
server {
location /api/ {
proxy_pass http://api_pool;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}Adding the backup parameter to a server line designates it as a standby that only receives traffic once every non-backup server in the upstream is marked unavailable, which is useful for a disaster-recovery region kept warm but otherwise idle. The down parameter, by contrast, manually and permanently marks a server as unavailable regardless of health status, which is the standard way to take a server out of rotation intentionally for planned maintenance without deleting its configuration line.
Cricket analogy: A backup server is like a twelfth man who only steps onto the field once a fielded player is genuinely unable to continue, while the down parameter is like a player being formally ruled out of the squad sheet before the toss.
Keepalive Connections to Upstream
By default nginx opens a new TCP connection to the upstream server for every proxied request and closes it afterward, which adds connection-setup latency and can exhaust ephemeral ports under high load. The keepalive directive inside an upstream block sets the maximum number of idle keepalive connections nginx retains per worker process to reuse for subsequent requests to that upstream; combined with proxy_http_version 1.1 and clearing the Connection header, this substantially reduces backend connection churn for high-throughput proxied traffic.
Cricket analogy: It's like a bowler warming up with a fresh run-up before every single delivery instead of staying at their mark between balls — keepalive is the equivalent of the bowler simply staying ready at the top of their mark, saving time each over.
keepalive only sets a per-worker cap on idle connections retained for reuse; it doesn't limit the total number of connections nginx can open to an upstream server, which is governed separately by your backend's own connection limits.
keepalive connections to upstream require proxy_http_version 1.1 and an empty Connection header (proxy_set_header Connection "";), since HTTP/1.0 and the default 'close' Connection value both force nginx to close the connection after every request.
- upstream blocks group backend servers, with max_fails and fail_timeout controlling passive health-check behavior.
- Passive checks only detect failures after a real client request fails; active checks (nginx Plus or third-party modules) probe proactively.
- The backup parameter marks a server as standby, used only once all non-backup servers are unavailable.
- The down parameter manually and permanently removes a server from rotation regardless of health status.
- keepalive in an upstream block caps idle connections retained per worker for reuse on future requests.
- keepalive requires proxy_http_version 1.1 and an emptied Connection header to actually take effect.
- Open-source nginx lacks built-in active health checks, unlike nginx Plus's health_check directive.
Practice what you learned
1. What do max_fails and fail_timeout control on an upstream server line?
2. What is the key limitation of passive health checks compared to active health checks?
3. What does the backup parameter on a server line do?
4. How does the down parameter differ from a server simply failing its health checks?
5. What two additional settings are required for the keepalive directive in an upstream block to actually take effect?
Was this page helpful?
You May Also Like
Load Balancing Algorithms
Understand nginx's round robin, weighted round robin, least_conn, and ip_hash load-balancing algorithms and when to use each.
Reverse Proxy Basics
Learn what a reverse proxy does, how nginx's proxy_pass directive rewrites request paths, and how to preserve client context with forwarded headers.
Proxying WebSockets with Nginx
Configure nginx to correctly upgrade and proxy long-lived WebSocket connections, including timeouts and load-balancing considerations.
Related Reading
Related Study Notes in DevOps
Browse all study notesAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics
DevOpsCI/CD Tools & Pipelines Study Notes
YAML · 37 topics