Configure NGINX for maximum performance with worker process optimization, advanced caching strategies, HTTP/2 tuning, and security hardening for high-traffic production environments.
Prerequisites
- Root or sudo access
- Existing NGINX installation
- SSL certificates for HTTPS/HTTP2
- Backend application servers
What this solves
High-traffic websites need NGINX configurations that go beyond default settings to handle thousands of concurrent connections efficiently. This tutorial covers advanced performance tuning including worker process optimization, memory management, caching strategies, HTTP/2 configuration, and security hardening that can dramatically improve response times and throughput for production environments.
Step-by-step configuration
Install performance monitoring tools
Start by installing tools to measure and monitor NGINX performance before and after optimization.
sudo apt update
sudo apt install -y htop iotop nginx-extras apache2-utils
Configure optimal worker processes and connections
Set worker processes to match CPU cores and optimize connection handling for maximum throughput.
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
nproc
Edit the main NGINX configuration with optimized worker settings:
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 100000;
pid /run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
accept_mutex off;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
keepalive_requests 1000;
reset_timedout_connection on;
client_body_timeout 10;
send_timeout 10;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Optimize memory management and buffer sizes
Configure buffer sizes to handle high-traffic loads efficiently and reduce memory fragmentation.
# Buffer optimization
client_body_buffer_size 16K;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
client_max_body_size 50M;
Output buffers
output_buffers 2 32k;
postpone_output 1460;
Proxy buffers
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_max_temp_file_size 1024m;
FastCGI buffers
fastcgi_buffering on;
fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;
fastcgi_busy_buffers_size 32k;
fastcgi_temp_file_write_size 256k;
fastcgi_max_temp_file_size 256m;
Open file cache
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
Configure advanced proxy caching
Set up intelligent caching with cache zones, purging capabilities, and conditional caching rules.
sudo mkdir -p /var/cache/nginx/{proxy,fastcgi}
sudo chown -R www-data:www-data /var/cache/nginx
# Proxy cache configuration
proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=my_cache:50m max_size=2g inactive=60m use_temp_path=off;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_methods GET HEAD POST;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
proxy_cache_background_update on;
FastCGI cache configuration
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=php_cache:100m max_size=5g inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_cache_valid 200 301 302 60m;
fastcgi_cache_valid 404 1m;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_cache_lock on;
fastcgi_cache_background_update on;
Cache bypass conditions
map $request_method $purge_method {
PURGE 1;
default 0;
}
map $http_cookie $no_cache {
~SESS 1;
~wordpress_logged_in 1;
default 0;
}
Enable HTTP/2 and SSL optimization
Configure HTTP/2 with SSL optimizations for better performance and security.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL Configuration
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
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;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
# HTTP/2 push optimization
http2_push_preload on;
http2_max_field_size 16k;
http2_max_header_size 32k;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy strict-origin-when-cross-origin;
# Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# Brotli compression (if available)
brotli on;
brotli_comp_level 6;
brotli_types
text/plain
text/css
application/json
application/javascript
text/xml
application/xml
application/xml+rss
text/javascript;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_bypass $no_cache;
proxy_no_cache $no_cache;
proxy_cache_purge $purge_method;
# Add cache status header
add_header X-Cache-Status $upstream_cache_status;
# Proxy headers
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;
# Connection settings
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_next_upstream_tries 3;
}
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt|tar|gz)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
Configure rate limiting and security
Implement rate limiting zones and DDoS protection mechanisms for high-traffic security.
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=global:10m rate=30r/s;
limit_req_zone $server_name zone=perserver:10m rate=100r/s;
Connection limiting
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_zone $server_name zone=perserver_conn:10m;
Request size limits
client_max_body_size 50M;
client_header_timeout 10;
client_body_timeout 10;
Hide server information
server_tokens off;
more_clear_headers Server;
Log suspicious activity
map $status $suspicious {
~^[45] 1;
default 0;
}
map $request_method $suspicious_method {
~^(TRACE|TRACK|DEBUG) 1;
default 0;
}
Geo-blocking example (customize as needed)
geo $blocked_country {
default 0;
# Add IPs or ranges to block if needed
}
Bot detection
map $http_user_agent $blocked_agent {
default 0;
~*malicious 1;
~*bot 1;
~*crawler 1;
~*spider 1;
}
Configure upstream load balancing
Set up intelligent load balancing with health checks and failover mechanisms.
upstream backend {
# Load balancing method
least_conn;
# Backend servers with weights
server 203.0.113.10:8080 weight=3 max_fails=3 fail_timeout=30s;
server 203.0.113.11:8080 weight=2 max_fails=3 fail_timeout=30s;
server 203.0.113.12:8080 weight=1 max_fails=3 fail_timeout=30s backup;
# Keep connections alive
keepalive 32;
keepalive_requests 1000;
keepalive_timeout 60s;
}
upstream php_backend {
server unix:/run/php/php8.2-fpm.sock weight=1 max_fails=3 fail_timeout=30s;
keepalive 16;
}
Configure advanced logging and monitoring
Set up detailed logging for performance analysis and security monitoring.
# Log formats
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format performance '$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" '
'cache=$upstream_cache_status';
log_format security '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'suspicious=$suspicious blocked_agent=$blocked_agent';
Access logs
access_log /var/log/nginx/access.log main buffer=64k flush=5s;
access_log /var/log/nginx/performance.log performance buffer=32k flush=10s if=$suspicious;
Error log
error_log /var/log/nginx/error.log warn;
Rate limit logging
limit_req_log_level warn;
limit_conn_log_level warn;
Apply rate limiting to server blocks
Add rate limiting rules to your site configuration with proper error handling.
sudo nano /etc/nginx/sites-available/optimized-site
Add these lines within your server block:
# Apply rate limits
limit_req zone=global burst=50 nodelay;
limit_req zone=perserver burst=100 nodelay;
limit_conn addr 10;
limit_conn perserver_conn 100;
Block suspicious requests
if ($blocked_country) {
return 403;
}
if ($blocked_agent) {
return 403;
}
Special handling for login endpoints
location /login {
limit_req zone=login burst=5 nodelay;
# Your login handling here
}
location /api/ {
limit_req zone=api burst=20 nodelay;
# Your API handling here
}
Enable the optimized configuration
Test the configuration and enable the new optimized site.
sudo nginx -t
sudo ln -sf /etc/nginx/sites-available/optimized-site /etc/nginx/sites-enabled/
sudo systemctl reload nginx
sudo systemctl status nginx
Configure system-level optimizations
Optimize kernel parameters and system limits for high-traffic performance.
# Network optimizations
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 65536 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10240 65535
File descriptor limits
fs.file-max = 2097152
www-data soft nofile 65535
www-data hard nofile 65535
nginx soft nofile 65535
nginx hard nofile 65535
sudo sysctl -p /etc/sysctl.d/99-nginx.conf
sudo systemctl restart nginx
Verify your setup
Test NGINX performance and verify all optimizations are working correctly.
# Check NGINX configuration
sudo nginx -t
Verify worker processes
ps aux | grep nginx
Test HTTP/2 support (if SSL configured)
curl -I --http2 https://example.com
Check cache directory permissions
ls -la /var/cache/nginx/
Monitor connections
ss -tuln | grep :80
ss -tuln | grep :443
Test rate limiting
ab -n 1000 -c 50 http://example.com/
Check log files
sudo tail -f /var/log/nginx/performance.log
Verify cache is working
curl -I http://example.com/
Look for X-Cache-Status header
Monitor system resources
htop
iotop
Check open file limits
cat /proc/$(pgrep nginx | head -1)/limits | grep files
Performance monitoring and analysis
You can set up comprehensive monitoring by integrating with Prometheus and Grafana for NGINX monitoring or implement centralized log analysis with Loki and Grafana for detailed performance insights.
Create performance monitoring script
Set up automated performance monitoring to track key metrics.
#!/bin/bash
echo "=== NGINX Performance Report ==="
echo "Date: $(date)"
echo
echo "Active Connections:"
curl -s http://localhost/nginx_status 2>/dev/null || echo "Stub status not configured"
echo
echo "Worker Processes:"
ps aux | grep '[n]ginx: worker' | wc -l
echo
echo "Memory Usage:"
ps aux | grep '[n]ginx' | awk '{sum += $6} END {printf "%.2f MB\n", sum/1024}'
echo
echo "Cache Statistics:"
if [ -d "/var/cache/nginx" ]; then
echo "Cache size: $(du -sh /var/cache/nginx | cut -f1)"
echo "Cache files: $(find /var/cache/nginx -type f | wc -l)"
else
echo "No cache directory found"
fi
echo
echo "Error Log (last 10 lines):"
tail -n 10 /var/log/nginx/error.log
sudo chmod +x /usr/local/bin/nginx-performance.sh
/usr/local/bin/nginx-performance.sh
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Worker process crashes | Insufficient memory or file descriptors | Check worker_rlimit_nofile and system limits in /etc/security/limits.conf |
| Cache not working | Permissions or path issues | sudo chown -R www-data:www-data /var/cache/nginx and verify paths |
| Rate limiting too aggressive | Burst values too low | Increase burst parameters in rate limit zones |
| SSL handshake failures | Cipher mismatch or certificate issues | Check SSL configuration and certificate validity |
| High memory usage | Buffer sizes too large | Adjust proxy_buffers and fastcgi_buffers based on actual traffic |
| Connection timeouts | Backend server overload | Check upstream health and adjust timeouts |
| HTTP/2 not working | Missing SSL or old OpenSSL | Verify SSL is enabled and OpenSSL version supports HTTP/2 |
Next steps
- Configure NGINX reverse proxy with advanced caching
- Implement NGINX Lua scripting for advanced caching logic
- Set up NGINX monitoring with Prometheus and Grafana
- Configure NGINX rate limiting and advanced security
- Optimize NGINX SSL performance for enterprise workloads