nginx load balancer config: share traffic between app servers
Split traffic across two or three copies of your app with an nginx upstream block.
A load balancer spreads visitors over several copies of your app so one copy is not overloaded and the site keeps working if one stops. In nginx you list the copies in an upstream block and send traffic to it with proxy_pass.
Create your config file
Type your own values. The file below updates as you type, and nothing you type leaves your browser.
upstream myapp_backend {
server 127.0.0.1:3001;
server 127.0.0.1:3002;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://myapp_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}How this setup works
Step-by-step setup
- Start your app copies so they listen on 127.0.0.1:3001 and 127.0.0.1:3002.
- Save the config above as /etc/nginx/conf.d/loadbalancer.conf.
- Test it: sudo nginx -t.
- Apply it: sudo systemctl reload nginx.
- Open http://example.com several times. Each app copy should log some of the requests.
- Stop one copy and reload the page to confirm the site still works.
What the important lines mean
- upstream myapp_backend is the named list of servers.
- With no method line nginx uses round robin, taking each server in turn.
- least_conn sends each request to the server with the fewest active connections.
- ip_hash keeps one visitor on one server, which helps when sessions are kept in memory.
Common errors and how to fix them
- 502 Bad Gateway
- nginx cannot reach any server in the list. Check each app is running on the address and port you entered, then read /var/log/nginx/error.log.
- no live upstreams while connecting to upstream
- Every server was marked as down after errors. Fix the apps, then reload nginx. nginx retries a failed server after 10 seconds by default.
- "upstream" directive is not allowed here
- The upstream block was placed inside a server block. It must sit at the top level, in the http section or a file in conf.d.
- Users keep getting logged out
- Each request may land on a different server that has no copy of the session. Use ip_hash, or store sessions in a shared place such as Redis.
- host not found in upstream
- nginx cannot resolve a hostname when it starts. Use an IP address, or fix the name.
Frequently asked questions
- What is round robin?
- nginx sends the first request to server 1, the second to server 2, and so on, then starts again. It is the default and fine for most apps.
- Does nginx check that servers are healthy?
- Open-source nginx only notices when a request fails. It then skips that server for a short time. Full active health checks need nginx Plus or another tool.
- Can nginx balance WebSockets?
- Yes, but you need the upgrade headers on the location. See the reverse proxy page for those lines.
Free tools that help
- Common ports listSearch a list of common TCP and UDP port numbers: SSH 22, HTTP 80, HTTPS 443, MySQL 3306, PostgreSQL 5432 and more, with dev server ports.
Fix a problem with this setup
- nginx 502 Bad GatewayFix nginx 502 Bad Gateway with Node, PHP-FPM or any proxy: read the error log, check the app is running and the port or socket matches.
- Node EADDRINUSEFix EADDRINUSE in Node, Express, Next.js and Vite: find the program using the port, stop it, or start on another port.
More server configs
- nginx rate limit configSlow down abusive visitors with limit_req: a request rate per IP, a burst, and a 429 answer.
- php.ini settingsSet the PHP values most sites need: upload size, memory, run time, errors, time zone and OPcache.
- MySQL my.cnf settingsA small MySQL or MariaDB override file for connections, memory, character set and the slow query log.
- nginx reverse proxy configSend visitors from port 80 to an app running on port 3000.
- nginx PHP-FPM configRun a PHP site (WordPress, Laravel or plain PHP) on nginx with PHP-FPM.
- Caddyfile reverse proxySend visitors to an app on port 3000 and get HTTPS certificates automatically.