Load balancing distributes incoming requests across multiple backend servers, preventing any single server from becoming a bottleneck and providing horizontal scalability and fault tolerance. Nginx supports four load balancing methods natively: round-robin (the default), least connections, IP hash (session persistence), and weight-based. The upstream block defines the pool of backend servers and their weights, and Nginx automatically detects unavailable backends and routes around them. On RHEL 9, Nginx load balancing is configured with zero additional packages — the upstream module is compiled in by default. This guide covers all four balancing methods, passive health checks, connection limits, and using Nginx as a TCP/UDP load balancer with stream blocks.
Prerequisites
- Nginx installed on RHEL 9
- Two or more backend application servers or ports to balance across
Step 1 — Round-Robin (Default)
Round-robin distributes requests to backends in sequence. The first request goes to server 1, the second to server 2, the third to server 3, then back to server 1:
upstream myapp {
server 10.0.0.10:8080;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://myapp;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Step 2 — Weighted Load Balancing
Use weight to send proportionally more traffic to more powerful servers:
upstream myapp {
server 10.0.0.10:8080 weight=3; # Gets 60% of traffic
server 10.0.0.11:8080 weight=2; # Gets 40% of traffic
}
Step 3 — Least Connections
Sends each request to the backend with the fewest active connections. Best for requests with varying processing times:
upstream myapp {
least_conn;
server 10.0.0.10:8080;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
Step 4 — IP Hash (Session Persistence)
Routes requests from the same client IP to the same backend server. Essential for stateful applications that store session data in memory:
upstream myapp {
ip_hash;
server 10.0.0.10:8080;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
Step 5 — Passive Health Checks and Failover
Nginx passively monitors backends. If a server fails to respond, it is marked as unavailable and traffic is routed to healthy servers:
upstream myapp {
server 10.0.0.10:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.11:8080 max_fails=3 fail_timeout=30s;
# Backup server — only used when primary servers are down
server 10.0.0.12:8080 backup;
# Remove a server from rotation permanently without deleting the config
server 10.0.0.13:8080 down;
}
max_fails=3 — number of consecutive failures before marking the server down. fail_timeout=30s — how long to wait before retrying a failed server.
Step 6 — Keepalive Connections to Backends
upstream myapp {
server 10.0.0.10:8080;
server 10.0.0.11:8080;
keepalive 32; # Maintain up to 32 idle connections per worker to backends
}
# Required with keepalive:
location / {
proxy_pass http://myapp;
proxy_http_version 1.1;
proxy_set_header Connection ""; # Clear the Connection header for keepalive
}
Step 7 — TCP/UDP Load Balancing with the stream Module
# Add to /etc/nginx/nginx.conf (outside the http block)
stream {
upstream mysql_cluster {
server 10.0.0.10:3306;
server 10.0.0.11:3306;
}
server {
listen 3306;
proxy_pass mysql_cluster;
}
}
Verification Checklist
nginx -t
systemctl reload nginx
# Test that requests reach different backends (check access logs on each)
for i in {1..6}; do curl -s http://app.example.com/whoami; done
Conclusion
Nginx load balancing on RHEL 9 requires only an upstream block — no additional modules or packages. Round-robin handles stateless applications; IP hash handles stateful sessions; least-conn handles mixed workloads; and the stream module extends load balancing to TCP/UDP services like MySQL. Passive health checks with max_fails and fail_timeout ensure traffic is automatically routed away from failed backends.
Next steps: How to Install and Configure Caddy Web Server on RHEL 9, How to Configure Nginx FastCGI Caching on RHEL 9, and How to Configure HAProxy for HTTP and TCP Load Balancing on RHEL 9.