Configure NGINX for high-traffic websites with microcaching for dynamic content, optimized worker processes, buffer tuning, and compression. Learn to monitor cache performance and troubleshoot memory usage.
Prerequisites
- Root or sudo access
- Basic NGINX knowledge
- Active web application or website
What this solves
NGINX performance optimization becomes critical when your website handles thousands of concurrent connections. Without proper tuning, default NGINX configurations can bottleneck at high traffic loads, causing slow response times and server resource exhaustion. This tutorial configures microcaching to reduce backend load, optimizes worker processes for your hardware, and implements compression to minimize bandwidth usage.
Step-by-step configuration
Update system packages
Start by updating your package manager to ensure you get the latest NGINX version and security patches.
sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx nginx-extras
Configure worker processes and connections
Optimize NGINX worker configuration based on your server's CPU cores and expected traffic load. This configuration handles up to 4096 concurrent connections per worker.
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
keepalive_requests 1000;
reset_timedout_connection on;
client_body_timeout 10;
send_timeout 2;
# Buffer optimization
client_max_body_size 50M;
client_body_buffer_size 1m;
client_header_buffer_size 4k;
large_client_header_buffers 8 8k;
output_buffers 8 256k;
postpone_output 1460;
# File handling
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Create cache directory structure
Set up dedicated cache directories with proper ownership for NGINX to store cached content and temporary files.
sudo mkdir -p /var/cache/nginx/microcache
sudo mkdir -p /var/cache/nginx/temp
sudo chown -R www-data:www-data /var/cache/nginx
sudo chmod -R 755 /var/cache/nginx
Configure microcaching for dynamic content
Create a microcaching configuration that caches dynamic content for short periods to reduce backend load while serving fresh content.
# Microcache zone configuration
proxy_cache_path /var/cache/nginx/microcache
levels=1:2
keys_zone=microcache:100m
max_size=1g
inactive=1h
use_temp_path=off;
Cache key definition
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
Rate limiting for cache misses
limit_req_zone $binary_remote_addr zone=cache_miss:10m rate=30r/m;
Upstream health monitoring
upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
keepalive 32;
}
Logging cache status
log_format cache_log '$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" '
'cs=$upstream_cache_status';
Configure gzip compression
Enable gzip compression for text-based content to reduce bandwidth usage and improve load times for clients.
# Gzip compression configuration
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_proxied any;
gzip_disable "msie6";
File types to compress
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json
application/xml
application/xhtml+xml
application/x-font-ttf
application/vnd.ms-fontobject
font/opentype
image/svg+xml
image/x-icon;
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;
Create optimized virtual host configuration
Configure a virtual host that implements microcaching, static file optimization, and performance monitoring.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 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;
# Document root
root /var/www/html;
index index.php index.html index.htm;
# Access logging with cache status
access_log /var/log/nginx/access.log cache_log;
error_log /var/log/nginx/error.log warn;
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 1M;
add_header Cache-Control "public, immutable";
add_header X-Cache-Status "STATIC";
access_log off;
# Enable gzip for static files
gzip_static on;
# Security for static files
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
add_header Vary Accept;
}
}
# PHP/Dynamic content with microcaching
location ~ \.php$ {
# Rate limiting for uncached requests
limit_req zone=cache_miss burst=10 nodelay;
# Microcache configuration
proxy_cache microcache;
proxy_cache_valid 200 301 302 5m;
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;
# Cache bypass conditions
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~ "/wp-admin/|/xmlrpc.php|wp-..php|/feed/|index.php|sitemap(_index)?.xml") { set $skip_cache 1; }
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $skip_cache 1; }
proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;
# Proxy headers
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;
proxy_set_header Host $http_host;
proxy_redirect off;
# Cache status header
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://backend;
}
# HTML files with short cache
location / {
try_files $uri $uri/ /index.php?$args;
# Short cache for HTML
location ~* \.html$ {
expires 5m;
add_header Cache-Control "public";
}
}
# Cache purge endpoint (restrict access)
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
proxy_cache_purge microcache "$scheme$request_method$host$1";
}
# Security locations
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\. { deny all; access_log off; log_not_found off; }
}
Enable the optimized configuration
Activate the new virtual host configuration and test the NGINX configuration for syntax errors.
sudo ln -s /etc/nginx/sites-available/optimized-site /etc/nginx/sites-enabled/
sudo nginx -t
Configure system limits for high traffic
Increase system limits to handle high connection loads without running out of file descriptors.
# NGINX user limits
www-data soft nofile 65536
www-data hard nofile 65536
www-data soft nproc 32768
www-data hard nproc 32768
[Service]
LimitNOFILE=65536
LimitNPROC=32768
sudo mkdir -p /etc/systemd/system/nginx.service.d
sudo systemctl daemon-reload
Start and enable NGINX with optimizations
Restart NGINX to apply all performance optimizations and enable it to start automatically on boot.
sudo systemctl restart nginx
sudo systemctl enable nginx
sudo systemctl status nginx
Configure log rotation for performance logs
Set up log rotation to prevent log files from consuming excessive disk space while maintaining performance monitoring data.
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 cat /var/run/nginx.pid
fi
endscript
}
Verify your setup
Test NGINX performance optimization and microcaching functionality with these verification commands:
# Check NGINX status and configuration
sudo nginx -t
sudo systemctl status nginx
Test cache functionality
curl -I http://example.com/
curl -I http://example.com/ # Second request should show cache hit
Check cache directory
ls -la /var/cache/nginx/microcache/
du -sh /var/cache/nginx/microcache/
Monitor worker processes
ps aux | grep nginx
Check connection limits
ulimit -n
Test gzip compression
curl -H "Accept-Encoding: gzip" -I http://example.com/
Monitor cache hit rates
tail -f /var/log/nginx/access.log | grep -o 'cs=[A-Z]*'
Monitor performance with access log analysis
Use these commands to analyze cache performance and identify optimization opportunities:
# Cache hit rate analysis
awk '/cs=HIT/ {hit++} /cs=MISS/ {miss++} /cs=BYPASS/ {bypass++} END {total=hit+miss+bypass; if(total>0) printf "Hit Rate: %.2f%% (Hits: %d, Misses: %d, Bypassed: %d)\n", (hit/total)*100, hit, miss, bypass}' /var/log/nginx/access.log
Response time analysis
awk '{print $NF}' /var/log/nginx/access.log | awk -F'=' '/rt=/ {gsub(/rt=/, "", $1); sum+=$1; count++} END {if(count>0) print "Avg Response Time:", sum/count "s"}'
Troubleshoot cache performance
Create a cache monitoring script to track performance metrics and identify issues:
#!/bin/bash
NGINX Cache Monitoring Script
CACHE_DIR="/var/cache/nginx/microcache"
LOG_FILE="/var/log/nginx/access.log"
echo "=== NGINX Cache Status ==="
echo "Cache directory size: $(du -sh $CACHE_DIR 2>/dev/null | cut -f1 || echo 'N/A')"
echo "Cache files count: $(find $CACHE_DIR -type f 2>/dev/null | wc -l || echo '0')"
echo "\n=== Memory Usage ==="
echo "NGINX processes memory usage:"
ps aux | awk '/nginx/ && !/awk/ {sum+=$6} END {print "Total RSS: " sum/1024 " MB"}'
sudo chmod +x /usr/local/bin/nginx-cache-monitor.sh
sudo /usr/local/bin/nginx-cache-monitor.sh
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Cache directory permission denied | Wrong ownership on cache directory | sudo chown -R www-data:www-data /var/cache/nginx |
| Low cache hit rate | Cache bypass conditions too aggressive | Review $skip_cache conditions in virtual host |
| High memory usage | Cache zone too large or inactive timeout too long | Reduce keys_zone size or inactive time |
| Connection limit errors | System file descriptor limits too low | Increase worker_rlimit_nofile and system limits |
| Slow backend connections | No keepalive to upstream | Add keepalive directive to upstream block |
| Static files not compressing | Missing gzip_static module | Install nginx-extras package for gzip_static support |
Next steps
- Setup nginx reverse proxy with SSL certificates and security hardening
- Configure NGINX rate limiting and DDoS protection with advanced security rules
- Configure NGINX HTTP/2 server push and connection multiplexing
- Implement NGINX Lua scripting for advanced caching logic
- Configure NGINX SSL certificate automation with Certbot and renewal monitoring
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# NGINX High-Performance Configuration Script
# Optimizes NGINX with microcaching, worker tuning, and compression
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Default configuration
BACKEND_IP="${1:-127.0.0.1:8080}"
CACHE_SIZE="${2:-1g}"
# Usage message
usage() {
echo "Usage: $0 [backend_ip:port] [cache_size]"
echo "Example: $0 127.0.0.1:8080 2g"
exit 1
}
# Error handling and cleanup
cleanup() {
echo -e "${RED}[ERROR] Script failed. Restoring original configuration...${NC}"
if [ -f /etc/nginx/nginx.conf.backup ]; then
mv /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf
fi
systemctl restart nginx 2>/dev/null || true
}
trap cleanup ERR
# Check if running as root/sudo
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root or with sudo${NC}"
exit 1
fi
# Auto-detect distribution
echo "[1/8] Detecting distribution..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
NGINX_USER="www-data"
NGINX_EXTRAS="nginx-extras"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
NGINX_USER="nginx"
NGINX_EXTRAS="nginx-mod-http-cache-purge"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
NGINX_USER="nginx"
NGINX_EXTRAS=""
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}Cannot detect distribution${NC}"
exit 1
fi
echo -e "${GREEN}Detected: $PRETTY_NAME${NC}"
# Update system and install NGINX
echo "[2/8] Updating system packages..."
eval $PKG_UPDATE
echo "[3/8] Installing NGINX and modules..."
if [ "$PKG_MGR" = "apt" ]; then
$PKG_INSTALL nginx $NGINX_EXTRAS
elif [ "$PKG_MGR" = "dnf" ]; then
$PKG_INSTALL nginx $NGINX_EXTRAS
else
$PKG_INSTALL nginx
fi
# Backup original configuration
echo "[4/8] Backing up original configuration..."
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
# Create cache directories
echo "[5/8] Creating cache directory structure..."
mkdir -p /var/cache/nginx/microcache
mkdir -p /var/cache/nginx/temp
chown -R $NGINX_USER:$NGINX_USER /var/cache/nginx
chmod -R 755 /var/cache/nginx
# Configure SELinux for cache directories (RHEL-based systems)
if command -v setsebool &> /dev/null; then
echo -e "${YELLOW}Configuring SELinux for NGINX cache...${NC}"
setsebool -P httpd_can_network_connect 1 2>/dev/null || true
semanage fcontext -a -t httpd_cache_t "/var/cache/nginx(/.*)?" 2>/dev/null || true
restorecon -R /var/cache/nginx 2>/dev/null || true
fi
# Create optimized NGINX configuration
echo "[6/8] Configuring NGINX performance settings..."
cat > /etc/nginx/nginx.conf << EOF
user $NGINX_USER;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
keepalive_requests 1000;
reset_timedout_connection on;
client_body_timeout 10;
send_timeout 2;
# Buffer optimization
client_max_body_size 50M;
client_body_buffer_size 1m;
client_header_buffer_size 4k;
large_client_header_buffers 8 8k;
output_buffers 8 256k;
postpone_output 1460;
# File handling
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Microcache zone configuration
proxy_cache_path /var/cache/nginx/microcache
levels=1:2
keys_zone=microcache:100m
max_size=$CACHE_SIZE
inactive=1h
use_temp_path=off;
# Cache key definition
proxy_cache_key "\$scheme\$request_method\$host\$request_uri\$is_args\$args";
# Rate limiting for cache misses
limit_req_zone \$binary_remote_addr zone=cache_miss:10m rate=30r/m;
# Upstream health monitoring
upstream backend {
server $BACKEND_IP max_fails=3 fail_timeout=30s;
keepalive 32;
}
# Gzip compression configuration
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_proxied any;
gzip_disable "msie6";
# File types to compress
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json
application/xml
application/xhtml+xml
application/atom+xml
image/svg+xml;
# Logging cache status
log_format cache_log '\$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" '
'cs=\$upstream_cache_status';
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
EOF
# Add sites-enabled include for Debian-based systems
if [ "$PKG_MGR" = "apt" ] && [ -d /etc/nginx/sites-enabled ]; then
echo " include /etc/nginx/sites-enabled/*;" >> /etc/nginx/nginx.conf
fi
echo "}" >> /etc/nginx/nginx.conf
# Test NGINX configuration
echo "[7/8] Testing NGINX configuration..."
nginx -t
# Start and enable NGINX
echo "[8/8] Starting and enabling NGINX service..."
systemctl enable nginx
systemctl restart nginx
# Configure firewall
if command -v ufw &> /dev/null; then
echo -e "${YELLOW}Configuring UFW firewall...${NC}"
ufw allow 'Nginx Full' 2>/dev/null || true
elif command -v firewall-cmd &> /dev/null; then
echo -e "${YELLOW}Configuring firewalld...${NC}"
firewall-cmd --permanent --add-service=http 2>/dev/null || true
firewall-cmd --permanent --add-service=https 2>/dev/null || true
firewall-cmd --reload 2>/dev/null || true
fi
# Verification checks
echo -e "${GREEN}Verifying installation...${NC}"
if systemctl is-active nginx >/dev/null 2>&1; then
echo -e "${GREEN}✓ NGINX is running${NC}"
else
echo -e "${RED}✗ NGINX is not running${NC}"
exit 1
fi
if [ -d /var/cache/nginx/microcache ]; then
echo -e "${GREEN}✓ Cache directories created${NC}"
fi
# Display system limits
echo -e "${YELLOW}System limits:${NC}"
echo "Worker processes: $(nproc)"
echo "Max connections per worker: 4096"
echo "Total max connections: $(($(nproc) * 4096))"
echo "Cache size: $CACHE_SIZE"
echo "Backend server: $BACKEND_IP"
echo -e "${GREEN}NGINX high-performance configuration completed successfully!${NC}"
echo -e "${YELLOW}Remember to:${NC}"
echo "1. Configure your site-specific settings in /etc/nginx/conf.d/"
echo "2. Monitor cache hit rates in access logs"
echo "3. Adjust cache size based on disk space and traffic patterns"
Review the script before running. Execute with: bash install.sh