nginx Load Balancing: upstream, Methods and Health Checks

To load balance with nginx, list your app servers in an upstream block and point proxy_pass at its name. Requests rotate round robin unless you add least_conn, ip_hash, hash or random. Each server line can carry a weight, max_fails and fail_timeout for passive health checks, and backup or down flags.

nginx load balancing methods
DirectiveHow it picks a serverGood for
(none)Weighted round robin, the defaultSimilar servers and short requests
least_connFewest active connections, weights taken into accountRequests of very different lengths
ip_hashHash of the client address (first three octets of IPv4, whole IPv6)Keeping a visitor on one server
hash keyHash of any value, such as $request_uriCache affinity; add consistent to limit reshuffling
randomRandom server, or best of two with random twoSeveral load balancers sharing one pool

Updated

Spreading traffic over several copies of an app is one of the oldest jobs nginx does, and the whole setup fits in a dozen lines. The builder below writes the upstream block from a list of servers, warns about combinations nginx rejects, and shows each server's share of requests when weights apply. The reference after it covers every server parameter with its default.

nginx upstream builder

List your servers, choose a method and copy a ready-to-paste upstream and proxy block. The share column shows how weighted round robin divides requests.

Share applies to round robin and is approximate for least_conn; hash methods depend on the keys.

server parameters and their defaults

Parameters on a server line inside upstream
ParameterDefaultEffect
weight=n1Relative share of requests
max_fails=n1Failed attempts within fail_timeout before the server is skipped; 0 disables
fail_timeout=time10sWindow for counting failures and how long the server is skipped
max_conns=n0 (no limit)Cap on simultaneous active connections to this server
backupoffUsed only when all primary servers are unavailable
downoffMarks the server permanently unavailable

Complete examples

Round robin with a spare

Two primaries share the load; the third only answers if both are out.

upstream app {
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;
    server 10.0.0.13:3000 backup;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://app;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

least_conn with reused connections

keepalive caches idle connections to the backends; the two proxy lines make that work.

upstream api {
    least_conn;
    server 10.0.0.21:8080 weight=2 max_fails=3 fail_timeout=30s;
    server 10.0.0.22:8080 max_fails=3 fail_timeout=30s;
    keepalive 16;
}

server {
    listen 80;
    location /api/ {
        proxy_pass http://api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_next_upstream error timeout http_502 http_503;
    }
}

Cache affinity by URL

Each URL keeps landing on the same cache server; consistent keeps most mappings intact when a server is added or removed.

upstream caches {
    hash $request_uri consistent;
    server 10.0.0.31:80;
    server 10.0.0.32:80;
    server 10.0.0.33:80;
}

Where the pieces go

The upstream block lives in the http context, next to your server blocks. It only names a pool; nothing happens until a location says proxy_pass http://name. The same pool can be used by many locations and many server blocks.

Passive health checks, step by step

When a request to a server fails in a way that proxy_next_upstream counts, nginx retries it on the next server and notes the failure. Once a server reaches max_fails failures within the fail_timeout window, nginx stops choosing it. After fail_timeout passes, it gently sends real client requests again, and a success puts it back in rotation.

Because the checks ride on real traffic, a visitor may hit the first failed attempt. Short timeouts on proxy_connect_timeout keep that delay small.

How it works

  1. Add each app server's address and port in the builder, with a weight if some machines are bigger than others.
  2. Pick a method. Leave it on round robin unless requests vary a lot in length or visitors must stick to one server.
  3. Copy the result into the http context, for example a file in conf.d, and run nginx -t.
  4. Reload with nginx -s reload, then stop one app server and watch requests move to the others.

Tips

Frequently asked questions

Does open source nginx have active health checks?

No. The health_check directive belongs to the commercial NGINX Plus. Open source nginx relies on passive checks: if a request to a server fails max_fails times within fail_timeout, the server is skipped for fail_timeout and then tried again with live traffic.

What are the defaults for max_fails and fail_timeout?

max_fails defaults to 1 and fail_timeout to 10 seconds. One failed attempt therefore takes a server out for ten seconds. Setting max_fails=0 turns the accounting off for that server.

How do I make sessions sticky in nginx?

Use ip_hash to keep each client address on one server, or hash with a cookie variable such as $cookie_session for finer control. Cookie-based sticky directives exist only in the commercial edition.

What does the weight parameter do?

It changes how many requests a server gets relative to the others. With weights 3, 1 and 1, the first server receives about three of every five requests under round robin. The default weight is 1.

Can nginx load balance WebSocket connections?

Yes. Point proxy_pass at the upstream and forward the Upgrade and Connection headers. least_conn suits long-lived sockets better than round robin, because it counts how many connections each server already holds.

Related: Apache vs nginx, Caddy vs nginx, WebSocket in Node.js, CDN explained, HTTP status codes.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap