Worker Tuning and Production Tips
Introduction
Default Nginx settings work for learning and small VPS hosts. As traffic grows, worker processes, connections, and keepalive tuning matter—along with how you organize config files for safe deploys. This chapter covers practical production defaults and team habits without premature micro-optimization.
Prerequisites
worker_processes and worker_connections
In /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
multi_accept on;
}Code explanation:
worker_processes auto— one worker per CPU core (typical)worker_connections— max simultaneous connections per worker- Rough max clients ≈
workers × connections(shared with upstream keepalive)
Raise cautiously on busy servers:
events {
worker_connections 2048;
}Also ensure ulimit -n (open files) is high enough in systemd unit or /etc/security/limits.conf.
Keepalive for Clients
http {
keepalive_timeout 65;
keepalive_requests 1000;
}Code explanation:
- Reuses TCP connections for browser HTTP/1.1
- Lower timeout frees resources on quiet sites; raise for high-traffic APIs rarely needed at edge
sendfile and TCP (Usually Default)
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}Already enabled on many distros—verify before duplicating. Helps static file throughput.
open_file_cache (Static Heavy Sites)
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;Caches file descriptors for frequently served static assets—optional on large static CDNs at origin.
Config Organization
One site per file
/etc/nginx/
├── nginx.conf
├── proxy_params
├── sites-available/
│ ├── api.example.com
│ └── www.example.com
└── sites-enabled/
└── api.example.com -> ../sites-available/api.example.comShared snippets
include /etc/nginx/proxy_params;
include /etc/letsencrypt/options-ssl-nginx.conf;Never commit privkey.pem or .htpasswd to Git—deploy via secure paths on server.
Environment-specific includes
include /etc/nginx/conf.d/*.conf;Staging vs production: separate files on each host, not commented blocks in one mega-file.
Deploy Workflow
- Edit config in
sites-available sudo nginx -tsudo systemctl reload nginxcurl -Ismoke test- Watch
error.logfor 60 seconds
Keep previous config backup:
sudo cp /etc/nginx/sites-available/api /etc/nginx/sites-available/api.bak.$(date +%F)Secrets and Keys
- TLS keys in
/etc/letsencrypt/— root-readable - API keys belong in app env—not Nginx config in repo
- Use
envfile on server + systemd for Spring Boot / Node
Capacity Planning (Rule of Thumb)
| Signal | Action |
|---|---|
| High CPU on nginx workers | Check gzip level, SSL, traffic volume; scale VPS or add CDN |
| Many 502/504 | Fix upstream; tune timeouts |
worker_connections errors in log | Raise limit + ulimit |
| Disk IO wait | Log rotation, access_log volume, static on CDN |
Measure with htop, access log rates, and APM on backends before tuning obscure directives.
X-Accel-Redirect (Awareness)
Nginx serves large files efficiently after app authorizes download:
location /protected-files/ {
internal;
alias /data/downloads/;
}App returns header X-Accel-Redirect: /protected-files/report.pdf—advanced pattern for file platforms.
Production Checklist
-
server_tokens off - HTTPS with auto-renewal
- Separate logs per major site
-
nginx -tin CI or deploy script for config templates - Firewall: 80/443 public; app ports localhost only
- Rate limits on auth endpoints
- Backups of config in
/etc/nginx
FAQ
worker_processes 1 for debug?
Yes on tiny VM—auto is normal in production.
Should I run multiple Nginx instances?
One per host is standard—scale horizontally with more VPS or load balancer.
Tuning without metrics?
Avoid guessing—use access log QPS, CPU, and upstream latency first.
Replace Nginx with CDN?
CDN caches static; origin Nginx still common for dynamic API proxy.
Config in Git?
Store sanitized templates; inject secrets on deploy. Cert paths differ per server.
When to restart vs reload?
reload for config; restart after package upgrade or if workers stuck.