Nginx Reverse Proxy — Cheat Sheet

Tags: nginx, reverse-proxy, devops, load-balancing, networking, http

Level: intermediate

TL;DR: Nginx acts as an intermediary terminating client traffic, routing HTTP/WebSocket requests to upstream backends, and handling SSL, caching, and header forwarding.

Key concepts

Reverse proxy sits in front of backend servers, routing client requests to internal services.

proxy_pass directive defines the upstream target URL or socket.

Terminates SSL/TLS connections to offload crypto overhead from application servers.

Preserves client IP addresses by forwarding standard headers like X-Forwarded-For.

Supports layer 7 load balancing algorithms including round-robin, least-connected, and IP hash.

Provides static file serving directly to avoid hitting application runtime layers.

Handles HTTP connection keepalive towards backends to reduce TCP handshake latency.

Protects upstream infrastructure by acting as a single public entry point and firewall.

Buffers client requests and responses to normalize slow clients and protect backends.

Upstream blocks allow grouping multiple application instances into a single logical target.

Typical questions and ready answers

Q: How do you pass the client's real IP to the backend service?R: I configure proxy_set_header X-Real-IP $remote_addr and proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for, and verify the backend framework trusts upstream proxy headers.

Q: What is the difference between URI slash handling in proxy_pass?R: If a URI path is included after the host in proxy_pass, Nginx replaces the matched location prefix with that URI; without a URI path, the full original request URI is passed untouched.

Q: How do you handle WebSockets through an Nginx reverse proxy?R: I explicitly forward the Upgrade and Connection headers by setting Upgrade $http_upgrade and Connection "upgrade" inside the location block.

Q: What load balancing algorithms does Nginx support natively?R: It defaults to weighted round-robin, and supports least_conn for connections in flight, ip_hash for session affinity, and hash for generic keys.

Pitfalls and common mistakes

Trailing slashes on proxy_pass alter request URI path resolution unexpectedly.

Missing Host header forward causes backend to generate redirects to upstream hostnames instead of the public domain.

client_max_body_size defaults to 1MB, throwing HTTP 413 on uploads if unconfigured.

Default proxy_read_timeout (60s) drops long-running upstream operations with 504 Gateway Timeout.

WebSocket requests fail if Upgrade and Connection hop-by-hop headers are not explicitly configured.

Upstream DNS changes are cached indefinitely unless dynamic resolver directives are used with variables.

Snippets and commands

# Test configuration syntax
nginx -t

# Reload configuration without dropping active connections
nginx -s reload

Nginx

# Standard upstream pool configuration
upstream backend_cluster {
    least_conn;
    server 10.0.0.10:3000 max_fails=3 fail_timeout=10s;
    server 10.0.0.11:3000 max_fails=3 fail_timeout=10s;
    keepalive 32;
}

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

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

    ssl_certificate /etc/ssl/certs/example.crt;
    ssl_certificate_key /etc/ssl/private/example.key;

    client_max_body_size 20M;

    location / {
        proxy_pass http://backend_cluster;
        proxy_http_version 1.1;

        # Header forwarding
        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;

        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # Buffering
        proxy_buffering on;
        proxy_buffer_size 8k;
        proxy_buffers 8 8k;
    }

    location /static/ {
        alias /var/www/static/;
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

To review

[ ] Header propagation flags for multi-tier proxies

[ ] Difference between root and alias inside location blocks

[ ] Dynamic DNS resolution in proxy_pass using variable assignment

[x] Basic SSL termination and HTTP-to-HTTPS redirect rule

[x] WebSocket upgrade configuration syntax

References

Nginx ngx_http_proxy_module documentation

RFC 7239: Forwarded HTTP Extension

Jarvis Interviews
Jarvis