Run several app instances behind Nginx — define an upstream pool, choose a balancing method (round-robin, least_conn, ip_hash), and keep traffic off unhealthy backends.
One app process can only handle so much. Run several copies on different ports (or machines), group them in an upstream block, and point proxy_pass at the group instead of a single address. Nginx spreads incoming requests across them, so you can serve far more traffic and survive one instance crashing.
# A pool of three app instances.
upstream app_servers {
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}
server {
listen 80;
location / {
proxy_pass http://app_servers; # balanced across the pool
}
}By default Nginx uses round-robin — each request goes to the next server in turn. least_conn sends each request to the server with the fewest active connections, which is better when requests vary in length. ip_hash pins each client IP to the same server ("sticky sessions"), useful if a server holds per-user state in memory. You can also weight a beefier server to take more traffic.
upstream app_servers {
least_conn; # favor the least-busy instance
# ip_hash; # OR: pin each client to one server
server 127.0.0.1:3001 weight=2; # gets twice the share
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}If an instance starts failing, you want Nginx to stop sending it traffic automatically. max_fails and fail_timeout do that passively: after N failed attempts within the window, Nginx marks the server down and stops using it for a while, then retries. A backup server only receives traffic when the primaries are all down.
upstream app_servers {
# Down after 3 fails in 30s; retried after the timeout.
server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3002 max_fails=3 fail_timeout=30s;
# Only used if both servers above are unavailable.
server 127.0.0.1:3009 backup;
}