nginx.conf Reference for Common Scenarios

Type: Software Reference Confidence: 0.94 Sources: 7 Verified: 2026-02-28 Freshness: 2026-02-28

TL;DR

Constraints

Quick Reference

DirectiveContextDefaultPurpose
worker_processesmainautoSet to CPU core count
worker_connectionsevents512Max connections per worker
server_tokenshttponSet to off to hide version
client_max_body_sizehttp/server1mMax upload size
proxy_passlocationBackend URL
proxy_set_header Hostlocation$proxy_hostSet to $host
ssl_protocolshttp/serverTLSv1.2 TLSv1.3TLS versions
ssl_certificateserverPath to fullchain.pem
ssl_session_cachehttpnoneSet to shared:SSL:10m
gziphttpoffEnable compression
limit_req_zonehttpRate limiting
upstreamhttpLoad balancer pool

Decision Tree

START
├── Serving static files only?
│   ├── YES → Static file server config
│   └── NO ↓
├── Proxying to one backend?
│   ├── YES → Single reverse proxy
│   └── NO ↓
├── Multiple backends?
│   ├── YES → Upstream load balancer
│   └── NO ↓
├── Need SSL termination?
│   ├── YES → SSL block with Let's Encrypt
│   └── NO ↓
└── DEFAULT → Reverse proxy + SSL + security headers

Step-by-Step Guide

1. Install nginx

Install on your platform. [src6]

sudo apt update && sudo apt install -y nginx

Verify: nginx -v → nginx version shown

2. Configure reverse proxy

Route to backend application. [src1]

server {
    listen 80;
    server_name example.com;
    server_tokens off;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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;
    }
}

Verify: sudo nginx -t && sudo nginx -s reload

3. Add SSL with Let's Encrypt

Enable HTTPS. [src2]

sudo certbot --nginx -d example.com

Verify: curl -I https://example.com → HTTP/2 200

4. Add rate limiting

Protect against abuse. [src5]

# In http block
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# In location
location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://backend;
}

Verify: send burst of requests, check for 429 responses

Code Examples

Static file server with caching

# Input:  Static file requests
# Output: Files with cache headers

server {
    listen 80;
    server_name static.example.com;
    root /var/www/static;
    server_tokens off;

    location ~* \.(css|js)$ { expires 1y; add_header Cache-Control "public, immutable"; }
    location ~* \.(png|jpg|svg|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; }
    location ~ /\. { deny all; return 404; }
}

Production reverse proxy + SSL + security

# Input:  Production nginx.conf
# Output: Hardened reverse proxy

user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;

events { worker_connections 4096; multi_accept on; }

http {
    include /etc/nginx/mime.types;
    server_tokens off;
    sendfile on;
    keepalive_timeout 65;

    gzip on;
    gzip_types text/plain text/css application/json application/javascript image/svg+xml;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;

    include /etc/nginx/conf.d/*.conf;
}

Anti-Patterns

Wrong: Using if for routing

# ❌ BAD — "if is evil" in nginx
location / {
    if ($request_uri ~* "/api") { proxy_pass http://api; }
}

Correct: Separate location blocks

# ✅ GOOD — explicit matching
location /api/ { proxy_pass http://api_backend; }
location / { proxy_pass http://web_backend; }

Wrong: Missing Host header

# ❌ BAD — backend sees proxy_host
location / { proxy_pass http://127.0.0.1:3000; }

Correct: Forward all headers

# ✅ GOOD — original context preserved
location / {
    proxy_pass http://127.0.0.1:3000;
    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;
}

Wrong: No security headers

# ❌ BAD — version exposed, no protection
server { listen 80; server_name example.com; }

Correct: Hardened headers

# ✅ GOOD — all protections enabled
server {
    listen 443 ssl http2;
    server_tokens off;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=63072000" always;
}

Common Pitfalls

Diagnostic Commands

# Test config syntax
sudo nginx -t

# Reload (zero-downtime)
sudo nginx -s reload

# Show compiled modules
nginx -V

# View access logs live
tail -f /var/log/nginx/access.log

# Check open connections
ss -tlnp | grep nginx

# Test SSL
openssl s_client -connect example.com:443 -tls1_2

# Check cert expiry
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

Version History & Compatibility

VersionStatusBreaking ChangesMigration Notes
nginx 1.27.xMainlineHTTP/3 improvementsLatest features
nginx 1.26.xStableNoneRecommended for production
nginx 1.24.xPrevious stableWidely deployed
OpenSSL 3.xCurrentDeprecated algorithmsRequired for TLS 1.3

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Reverse proxy for any backendNeed automatic HTTPSCaddy
High-performance static servingSimple dev proxywebpack-dev-server, Vite
Load balancingService meshEnvoy, Istio
SSL terminationEdge computeCloudflare Workers
Rate limitingFull WAFModSecurity, Cloudflare WAF

Important Caveats

Related Units