Nginx as a Reverse Proxy: Load Balancing, Caching, and Security

Nginx handles more than a third of all web traffic, not because it's the flashiest tool, but because it's ruthlessly efficient at what it does. A properly tuned Nginx reverse proxy sits in front of your application servers, handling SSL termination, load balancing, caching, and security enforcement with minimal resource overhead.
Core Reverse Proxy Configuration
At its simplest, a reverse proxy forwards requests to a backend service. Nginx excels here because its event-driven architecture handles thousands of concurrent connections with a single worker process:
upstream app_backend {
server 10.0.1.10:3000 weight=3;
server 10.0.1.11:3000 weight=2;
server 10.0.1.12:3000 backup;
keepalive 32;
}
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
}
The upstream block defines the backend pool with optional weighting. The backup server only receives traffic when all primary servers are unhealthy. The keepalive directive maintains persistent connections to backend servers, reducing connection overhead per request.
SSL Termination and HTTP/2
Terminating SSL at the proxy offloads CPU-intensive cryptographic operations from application servers. Modern TLS configuration should disable deprecated protocols and prefer modern ciphers:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
Enable HTTP/2 (http2 on the listen directive) for multiplexed connections that reduce head-of-line blocking. Combined with SSL session caching, this cuts TLS handshake overhead dramatically for repeat visitors.
Caching Static and Dynamic Content
Nginx's caching layer reduces load on application servers for both static assets and API responses:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m
max_size=1g inactive=60m use_temp_path=off;
location /api/ {
proxy_cache api_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 5m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502;
proxy_cache_background_update on;
proxy_pass http://app_backend;
# Cache busting headers
add_header X-Cache-Status $upstream_cache_status;
}
The proxy_cache_use_stale directive serves stale content while updating the cache in the background—critical for avoiding thundering herd problems when a cached item expires and multiple requests hit the backend simultaneously. Add X-Cache-Status to responses so you can verify caching behavior during development.
Rate Limiting and Abuse Prevention
Protect your backends from traffic spikes and abuse with Nginx's rate-limiting module:
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn addr 10;
limit_conn_status 429;
proxy_pass http://app_backend;
}
}
The zone stores connection state in shared memory. The burst parameter allows short traffic spikes above the average rate—requests beyond the burst receive 429 Too Many Requests.
WebSocket Proxying
Nginx handles WebSocket upgrades naturally with the correct header configuration. The key directives are already shown in the base config above: Upgrade and Connection headers must pass through. For long-lived WebSocket connections, increase timeouts:
location /ws/ {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
}
Security Headers and Hardening
Minimal security headers every reverse proxy should emit:
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "0";
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()";
# Hide Nginx version
server_tokens off;
# Limit request body size
client_max_body_size 10m;
# Timeouts
client_body_timeout 12s;
client_header_timeout 12s;
send_timeout 10s;
Deploy Nginx with Confidence
Nginx as a reverse proxy gives your application a hardened, caching, load-balanced entry point that handles millions of requests on modest hardware. Our infrastructure team at SoniNow configures and tunes Nginx deployments for performance and security.
Related Insights

Caching Strategies for Web Applications: Browser Cache, CDN, and Application Cache
A complete guide to web caching strategies including browser cache control, CDN configuration, service worker caching, application-level caching, and cache invalidation patterns.

CI/CD Pipeline Design: Automating Build, Test, and Deployment Workflows
A guide to designing CI/CD pipelines that automate build, test, and deployment including GitHub Actions, GitLab CI, environment strategies, and rollback patterns.

CI/CD Pipeline for Next.js: GitHub Actions to Vercel and Docker Deployments
A step-by-step guide to building CI/CD pipelines for Next.js applications using GitHub Actions including automated testing, preview deployments, Docker builds, and production rollouts.