NGINX: High-Performance Reverse Proxy, Load Balancing, and Edge Caching

NGINX is an event-driven, asynchronous, non-blocking web server, reverse proxy, and Layer 7 load balancer. Originally built to solve the C10k problem (handling 10,000+ concurrent connections), it serves as the primary ingress edge for millions of modern cloud architectures.


⚡ Quick Dive

Load Balancing Algorithms Reference

Method Directive Balancing Behavior Ideal Use Case
Round Robin Default (no directive) Requests distributed sequentially across backend nodes Identical backend pool capacity
Least Connections least_conn; Routes request to server with fewest active connections Long-lived WebSocket or database queries
IP Hash ip_hash; Client IPv4/v6 address determines server selection Stateful apps requiring Sticky Sessions
Generic Hash hash $request_uri consistent; Hashes arbitrary key with consistent hashing Distributed caching layers
Weighted server srv1 weight=3; Proportionately biases traffic allocation Mixed-capacity hardware pools

Production Reverse Proxy Template

upstream api_backend {
    least_conn;
    server 10.0.1.10:8080 weight=3 max_fails=3 fail_timeout=10s;
    server 10.0.1.11:8080 weight=2 max_fails=3 fail_timeout=10s;
    server 10.0.1.12:8080 backup; # Standby server used only if primaries fail
    keepalive 32; # Cache up to 32 idle connections to upstream
}

server {
    listen 80;
    listen [::]:80;
    server_name api.example.com;
    return 301 https://$host$request_uri; # Force TLS redirect
}

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

    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location / {
        proxy_pass http://api_backend;
        proxy_http_version 1.1; # Required for keepalive
        proxy_set_header Connection "";
        
        # Forward original client headers to backend
        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 and Buffers
        proxy_connect_timeout 5s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
    }
}

📖 Extended Guide

1. Reverse Proxy Header Propagation

When Nginx proxies a request, the backend application sees Nginx's internal IP address instead of the end-user's real IP address. Proper header forwarding is critical:

User (203.0.113.195) ──► Nginx (10.0.0.5) ──► Backend App (10.0.1.10)
  • X-Real-IP $remote_addr: Passes the immediate client's IP.
  • X-Forwarded-For $proxy_add_x_forwarded_for: Appends the client IP to any existing proxy chain (e.g. 203.0.113.195, 10.0.0.5).
  • X-Forwarded-Proto $scheme: Informs backend whether user connected over http or https (preventing infinite redirect loops in backend frameworks).

2. Rate Limiting & DoS Mitigation

Protect backend applications from brute-force attacks and traffic spikes using the Leaky Bucket algorithm:

# Define rate limiting zone: 10 requests per second per client IP
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

server {
    location /login/ {
        # Allow sudden bursts of up to 20 requests without delay
        limit_req zone=api_limit burst=20 nodelay;
        limit_req_status 429; # Return HTTP 429 Too Many Requests

        proxy_pass http://api_backend;
    }
}

3. Edge Content Caching Architecture

# Define cache zone in RAM (100MB metadata) pointing to disk storage (10GB max)
proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=API_CACHE:100m max_size=10g inactive=60m use_temp_path=off;

server {
    location /static/ {
        proxy_pass http://api_backend;
        proxy_cache API_CACHE;
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_use_stale error timeout updating http_500 http_502;
        add_header X-Cache-Status $upstream_cache_status;
    }
}