You already know the basics: worker_processes auto, enable gzip, and bump up a few buffers. In production, though, naive defaults can leave performance on the table—or worse, waste memory and slow down during traffic spikes. This guide skips the primer and dives into advanced tuning of workers, gzip, and buffers for experienced sysadmins running Nginx in 2026.
Worker Process Tuning
worker_processes and CPU Affinity
The auto setting binds one process per CPU core. But is that always optimal? For workloads with heavy SSL termination or disk I/O, you may benefit from setting worker_processes equal to the number of physical cores (not hyperthreads) to reduce context switching. Use worker_cpu_affinity to pin processes to specific cores for cache locality.
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
Edge case: On virtualized environments with CPU stealing, experiment with one fewer worker than virtual CPUs to leave headroom for system processes.
worker_connections and the Event Model
The classic formula max_clients = worker_processes * worker_connections holds, but modern Nginx uses epoll (Linux) or kqueue (BSD). Raise worker_connections to 4096 or higher if you have ample file descriptors. But watch out—each connection consumes memory for buffers and socket structures. Monitor RSS and /proc/meminfo.
events {
use epoll;
worker_connections 8192;
multi_accept on;
accept_mutex off; # for epoll, mutex can add latency
}
multi_accept and accept_mutex
multi_accept on: Accept multiple new connections in a single event loop iteration. Reduces latency under bursty traffic.accept_mutex off: With epoll, the accept mutex is unnecessary and can cause thundering herd. Disable it for most modern kernels.
Event Loop Tuning
If you serve WebSocket or long-lived connections, consider worker_aio_requests and direct I/O for Linux AIO. For high concurrency, tune epoll_events (the number of events retrieved per syscall) to 512.
events {
epoll_events 512;
worker_aio_requests 32;
}
Gzip Optimization
Compression Level vs CPU Impact
gzip_comp_level 5 is the sweet spot for most servers. Level 6+ gives diminishing returns and can burn CPU on dynamic responses. For static assets, precompress (see below).
gzip_types – Only What You Need
Don't gzip already compressed types (images, video). Include only text-like MIME types:
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/rss+xml application/atom+xml font/ttf font/otf image/svg+xml;
Add image/svg+xml—SVG compresses well. Omit text/html (enabled by default).
gzip_min_length – Avoid Tiny Files
Set a minimum response length (e.g., 1000 bytes) to skip gzipping small responses where overhead outweighs gain.
gzip_proxied – Edge Cases
Use gzip_proxied any; if you have CDNs or reverse proxies that may add Via headers. Better: expired no-cache no-store private auth; to only compress responses that are cacheable.
Static Gzip Precompression
Serve .gz files directly using gzip_static on;. Use with open_file_cache to avoid repeated disk reads.
server {
location /static/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
}
Build gzip versions as part of your deployment pipeline.
gzip_buffers and Memory
Default gzip_buffers 32 4k; uses up to 128 KB per request. For large responses, increase buffers to reduce allocation overhead. But beware: each worker can have many concurrent compressions.
gzip_buffers 64 8k;
Disabling Gzip for Specific User Agents
Some bots or old clients report gzip support but break. Use gzip_disable "msie6" and gzip_disable "legacy"; with custom regex patterns.
Buffer Tuning
proxy_buffer_size – Headers
The default (4k) is often too small for large headers (e.g., many cookies, JWT tokens). Increase to 8k or 16k to avoid 502 errors.
proxy_buffer_size 8k;
proxy_buffers 8 8k;
proxy_buffers – Response Body
Each buffer is used to store upstream response data before sending to client. For backends that send large responses, increase the number and size. But memory per connection = proxy_buffers * proxy_buffer_size + proxy_busy_buffers_size. Monitor worker memory.
large_client_header_buffers
Controls maximum size and quantity for client request headers. Default 4 8k is usually sufficient. For apps with long cookie chains, increase to 8 16k. Set large_client_header_buffers 4 16k;.
client_body_buffer_size and client_max_body_size
client_body_buffer_size handles buffering of request bodies. If your app receives large uploads, set it to a multiple of 16k (page size). Use client_body_in_file_only on; for very large uploads to spill to disk.
client_body_buffer_size 128k;
client_max_body_size 20m;
output_buffers and fastcgi_buffering
For FastCGI backend, use fastcgi_buffers 8 8k and fastcgi_busy_buffers_size 16k. fastcgi_buffering on is default; turning it off can reduce memory but increase latency.
sendfile and tcp_nopush
sendfile on copies data from disk directly to network socket, zero-copy. tcp_nopush on combines multiple packets before sending, improving throughput. Always enable both.
Advanced Edge Cases
SSL/TLS Buffer Tuning
sndbuf and rcvbuf for TLS: ssl_buffer_size 4k is optimal for most web traffic. For maximum throughput, match the kernel socket buffer (net.core.rmem_max). Set proxy_buffer_size larger to accommodate TLS handshake certificates if you proxy through HTTPS.
Handling Upstream Response Buffering
Disable proxy buffering for real-time applications that need immediate streaming (Server-Sent Events, WebSocket). Use proxy_buffering off; but be aware of memory for non-buffered reads.
Combatting Slow Client Attacks
Set client_body_timeout 60s; and client_header_timeout 60s; to limit slowloris. Adjust send_timeout 60s; for slow responses. Use limit_conn and limit_req to control rate.
Keep-Alive Tuning
keepalive_requests 1000; and keepalive_timeout 65s; are good for high reuse. For public-facing, consider lowering timeout to 10s to free connections faster.
Conclusion
Advanced Nginx tuning is a balancing act between throughput, latency, and resource consumption. Test each change under realistic load—what works for a static file server may hurt a dynamic API. Use tools like strace, ngxtop, and top -H to pinpoint bottlenecks. The configs above provide a starting point for 2026-ready performance. Remember: fewer, larger buffers with sendfile and precompressed content often outperform generic defaults. Profile, iterate, and optimize.
