Home/Engineer/Networking / Servers/Advanced Nginx Operations — …
Networking / ServersAdvancedUbuntuDebianCentOSRHELNginxrate-limiting

Advanced Nginx Operations — Load Balancing · Caching · Rate Limiting · Security Headers

A deep-dive guide to taking full control of production Nginx — covering upstream load-balancing strategies, proxy_cache content caching, limit_req rate limiting, and security headers.

Contents
  1. Production Nginx Configuration Structure
  2. 1. Upstream Load-Balancing Strategies
  3. 2. proxy_cache — Content Caching
  4. 3. Rate Limiting — DDoS / Brute-Force Defense
  5. 4. Security Headers and SSL Hardening
  6. 5. Performance Tuning — Worker and Connection Optimization

Production Nginx Configuration Structure

Beyond a simple reverse proxy, this guide covers patterns for using Nginx as a load balancer, cache server, and a front-line layer in front of a WAF.


1. Upstream Load-Balancing Strategies

Basic Configuration (Round Robin)

Nginx
http {
  upstream app_servers {
    least_conn;          # Distribute by fewest connections (recommended over Round Robin)

    server 10.0.1.10:8080 weight=3;   # Weight: 30% of traffic
    server 10.0.1.11:8080 weight=2;
    server 10.0.1.12:8080 weight=1;
    server 10.0.1.13:8080 backup;     # Used when all others are down

    keepalive 32;        # upstream keepalive connection pool
    keepalive_timeout 60s;
  }

  server {
    listen 443 ssl http2;
    server_name api.example.com;

    location / {
      proxy_pass http://app_servers;
      proxy_http_version 1.1;
      proxy_set_header Connection "";         # preserve keepalive
      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;
    }
  }
}

Session Persistence (Sticky Sessions)

Nginx
upstream app_servers {
  ip_hash;              # Same client IP always goes to the same server
  server 10.0.1.10:8080;
  server 10.0.1.11:8080;
}

Health Checks (Manual Implementation Without Nginx Plus)

Nginx
upstream app_servers {
  server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
  server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
}
# max_fails: temporarily exclude the server after 3 failures within 30 seconds

2. proxy_cache — Content Caching

Nginx
http {
  # Define the cache store (top-level http block in nginx.conf)
  proxy_cache_path /var/cache/nginx
    levels=1:2                    # directory hierarchy
    keys_zone=app_cache:50m       # 50MB in-memory key store
    max_size=10g                  # maximum disk usage
    inactive=60m                  # delete if not accessed for 60 minutes
    use_temp_path=off;

  server {
    location / {
      proxy_pass http://app_servers;

      proxy_cache app_cache;
      proxy_cache_key "$scheme$request_method$host$request_uri";
      proxy_cache_valid 200 302 10m;   # cache 200/302 responses for 10 minutes
      proxy_cache_valid 404      1m;
      proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
      proxy_cache_lock on;             # prevent duplicate requests for the same key (thundering herd)
      proxy_cache_lock_timeout 5s;

      # expose cache status header (for debugging)
      add_header X-Cache-Status $upstream_cache_status;
    }

    # Cache bypass: under specific conditions
    location /api/user {
      proxy_pass http://app_servers;
      proxy_cache_bypass $cookie_session;  # skip cache if a session cookie is present
      proxy_no_cache $cookie_session;
    }

    # Cache purge (internal only)
    location ~ /purge(/.*) {
      allow 127.0.0.1;
      deny all;
      proxy_cache_purge app_cache "$scheme$request_method$host$1";
    }
  }
}
Bash
# Check cache status
curl -I https://example.com/static/logo.png | grep X-Cache-Status
# HIT / MISS / BYPASS / UPDATING

# Check cache directory size
du -sh /var/cache/nginx

# Flush the entire cache
sudo rm -rf /var/cache/nginx/*
sudo nginx -s reload

3. Rate Limiting — DDoS / Brute-Force Defense

Nginx
http {
  # Define request rate-limit zones
  limit_req_zone $binary_remote_addr zone=api_limit:20m rate=10r/s;
  limit_req_zone $binary_remote_addr zone=login_limit:10m rate=3r/m;
  limit_req_zone $http_x_api_key    zone=key_limit:10m  rate=100r/s;

  # Connection-count limit zone
  limit_conn_zone $binary_remote_addr zone=conn_limit:20m;

  server {
    # API endpoint: 10 req/s, burst of 20 allowed
    location /api/ {
      limit_req zone=api_limit burst=20 nodelay;
      limit_conn conn_limit 20;
      limit_req_status 429;

      proxy_pass http://app_servers;
    }

    # Login: 3 per minute; queue on excess (no nodelay)
    location /auth/login {
      limit_req zone=login_limit burst=5;
      limit_req_status 429;
      proxy_pass http://app_servers;
    }

    # Customize the rate-limit exceeded response
    error_page 429 /rate_limit.json;
    location = /rate_limit.json {
      internal;
      default_type application/json;
      return 429 '{"error":"Too Many Requests","retry_after":60}';
    }
  }
}

4. Security Headers and SSL Hardening

Nginx
http {
  # TLS settings
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers off;
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';

  # HSTS (Strict-Transport-Security)
  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

  # Generate and apply DH parameters
  ssl_dhparam /etc/nginx/dhparam.pem;    # openssl dhparam -out /etc/nginx/dhparam.pem 4096

  # OCSP Stapling
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.8.8 8.8.4.4 valid=300s;

  server {
    # Apply security headers in bulk
    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 "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com; img-src 'self' data: cdn.example.com; style-src 'self' 'unsafe-inline';" always;

    # Hide server information
    server_tokens off;

    # HTTP → HTTPS redirect
    if ($scheme = http) {
      return 301 https://$host$request_uri;
    }
  }
}

5. Performance Tuning — Worker and Connection Optimization

Nginx
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;          # Auto-set to match CPU core count
worker_rlimit_nofile 65535;     # file descriptor limit

events {
  worker_connections 4096;      # max connections per worker
  use epoll;                    # Linux-optimized event method
  multi_accept on;              # accept multiple connections at once
}

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;

  keepalive_timeout 65;
  keepalive_requests 1000;

  # Gzip compression
  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss;
  gzip_min_length 1024;

  # Buffer tuning
  proxy_buffer_size 128k;
  proxy_buffers 4 256k;
  proxy_busy_buffers_size 256k;

  # Timeouts
  proxy_connect_timeout 5s;
  proxy_send_timeout 60s;
  proxy_read_timeout 60s;
}
Bash
# Validate configuration
sudo nginx -t

# Zero-downtime config reload
sudo nginx -s reload

# Real-time connection stats
sudo nginx -V 2>&1 | grep with-http_stub_status
# Check the status page
curl http://localhost/nginx_status
#Nginx#rate-limiting
Editorial note

AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us

Topic-related official docs (auto-linked · not per-claim sources)NGINX documentation ↗OWASP documentation ↗

Questions & answers

Ask a question about this guide. We'll review and reply.