Nginx has become the web server of choice for high-traffic websites, serving over 40% of the top 10,000 websites globally. Its event-driven architecture and low memory footprint make it ideal for modern web applications. This guide explores advanced Nginx configuration techniques and performance optimization strategies for production environments.
Understanding Nginx Architecture
Nginx uses an asynchronous event-driven architecture, fundamentally different from Apache’s process/thread-per-connection model. This design enables Nginx to handle thousands of concurrent connections with minimal memory usage[1].
Master-Worker Process Model
Master Process (root)
├── Worker Process 1
├── Worker Process 2
├── Worker Process 3
└── Worker Process 4
- Master: Reads configuration, manages workers, handles signals
- Workers: Handle actual connections (one per CPU core optimal)
Configuration Optimization
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto; # Auto-detect CPU cores
worker_rlimit_nofile 65535; # Max open files per worker
events {
worker_connections 4096; # Max connections per worker
use epoll; # Linux kernel 2.6+ (efficient)
multi_accept on; # Accept multiple connections at once
}
http {
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
types_hash_max_size 2048;
server_tokens off; # Hide Nginx version
# Buffer sizes
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# Timeouts
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
# Logging
access_log /var/log/nginx/access.log combined buffer=32k flush=5s;
error_log /var/log/nginx/error.log warn;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
gzip_disable "msie6";
# Include virtual hosts
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Caching Strategies
FastCGI Caching
Cache PHP-FPM responses for dramatic performance improvements:
## Define cache zone
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=PHPCACHE:100m
inactive=60m
max_size=1g;
server {
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_cache PHPCACHE;
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 404 10m;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_bypass $http_pragma $http_authorization;
fastcgi_no_cache $http_pragma $http_authorization;
# Cache headers
add_header X-Cache-Status $upstream_cache_status;
# Cache key
fastcgi_cache_key "$scheme$request_method$host$request_uri";
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Proxy Caching
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=PROXYCACHE:10m
max_size=10g
inactive=60m
use_temp_path=off;
server {
location / {
proxy_pass http://backend;
proxy_cache PROXYCACHE;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
}
}
Static File Caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
Load Balancing
Nginx excels as a reverse proxy and load balancer:
upstream backend {
# Load balancing method
least_conn; # or: ip_hash, hash $request_uri, random
# Backend servers
server 10.0.0.10:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.0.11:8080 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.0.12:8080 backup; # Backup server
# Keepalive connections
keepalive 32;
keepalive_timeout 60s;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
# Timeouts
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Buffering
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
}
}
| Method | Algorithm | Use Case |
|---|---|---|
| round_robin | Distributes evenly | Default, works well for homogeneous backends |
| least_conn | Fewest active connections | Varying request durations |
| ip_hash | Hash client IP | Session persistence without sticky cookies |
| hash | Hash custom variable | Content-based routing |
| random | Random selection | Simple randomization |
SSL/TLS Optimization
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# Certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Modern configuration (Mozilla SSL Config Generator)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1 valid=300s;
resolver_timeout 5s;
# Session cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
}
Rate Limiting
Protect your server from abuse:
## Define rate limit zones
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
## Connection limits
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location / {
limit_req zone=general burst=20 nodelay;
limit_conn conn_limit 10;
}
location /api/ {
limit_req zone=api burst=50;
}
location /login {
limit_req zone=login burst=2;
}
}
HTTP/2 and HTTP/3
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen 443 quic reuseport; # HTTP/3
listen [::]:443 quic reuseport;
http2_push_preload on;
http3 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
}
Monitoring and Logging
## Enable stub_status module
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status;
access_log off;
allow 127.0.0.1;
deny all;
}
}
## Custom log format
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/detailed.log detailed;
Security Best Practices
## Block common exploits
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ ~$ {
deny all;
access_log off;
}
## Prevent access to sensitive files
location ~* \.(sql|bak|old|conf)$ {
deny all;
}
## Limit request methods
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
## Block user agents
if ($http_user_agent ~* (nmap|nikto|wikto|sf|sqlmap|bsqlbf|w3af|acunetix|havij|appscan)) {
return 403;
}
Performance Benchmarking
## Test with ab (Apache Bench)
ab -n 10000 -c 100 https://example.com/
## Test with wrk
wrk -t4 -c100 -d30s https://example.com/
## Monitor real-time stats
watch -n 1 'curl -s http://127.0.0.1/nginx_status'
## Analyze logs
goaccess /var/log/nginx/access.log -o report.html --log-format=COMBINED
Related Articles
- Apache vs Nginx: Choosing the Right Webserver
- HTTP/2 and HTTP/3 Implementation Guide
- PostgreSQL Performance Tuning and Optimization Techniques
Conclusion
Nginx’s performance and flexibility make it ideal for modern web architectures. Proper configuration can handle millions of requests per day on modest hardware.
Key recommendations:
- Use worker_processes auto for CPU optimization
- Enable FastCGI/proxy caching for dynamic content
- Implement rate limiting to prevent abuse
- Use HTTP/2 and consider HTTP/3
- Enable gzip compression
- Configure SSL/TLS properly
- Monitor with stub_status and detailed logging
- Regular security audits and updates
With proper tuning, Nginx can serve 100,000+ requests per second on high-end hardware while maintaining sub-millisecond response times.
References
[1] NGINX, Inc. (2024). NGINX Documentation. Available at: https://nginx.org/en/docs/ (Accessed: November 2025)
[2] Reese, W. (2008). Nginx: The High-Performance Web Server and Reverse Proxy. Linux Journal. Available at: https://www.linuxjournal.com/article/10108 (Accessed: November 2025)