Nginx Complete Guide 2026: Reverse Proxy, Load Balancing, and SSL
Advertisement
Nginx 2026: The Production Web Server
Nginx handles 34% of all web traffic. As a reverse proxy for Node.js, it adds SSL, caching, rate limiting, and load balancing without changing your application code.
- Installation
- Reverse Proxy for Node.js
- Load Balancing
- Rate Limiting
- Nginx as Static File Server
- Let's Encrypt SSL (Free)
- Nginx Performance Tuning
Installation
sudo apt update
sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx
Reverse Proxy for Node.js
# /etc/nginx/sites-available/myapp
upstream nodejs_app {
server 127.0.0.1:3000;
keepalive 64; # Persistent connections
}
server {
listen 80;
server_name webcoderspeed.com www.webcoderspeed.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name webcoderspeed.com www.webcoderspeed.com;
# SSL
ssl_certificate /etc/letsencrypt/live/webcoderspeed.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/webcoderspeed.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# Client body limit
client_max_body_size 10M;
# Proxy to Node.js
location / {
proxy_pass http://nodejs_app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade'; # WebSocket support
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;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Static files — serve directly from Nginx (faster)
location /_next/static/ {
alias /app/.next/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /public/ {
alias /app/public/;
expires 30d;
}
}
Load Balancing
upstream api_servers {
# Load balancing methods:
# (default) round-robin
# least_conn; — fewest active connections
# ip_hash; — same client always hits same server
least_conn;
server 10.0.1.10:3000 weight=3; # Gets 3x traffic
server 10.0.1.11:3000 weight=1;
server 10.0.1.12:3000 backup; # Only used when others fail
keepalive 32;
# Health checks
server 10.0.1.10:3000;
server 10.0.1.11:3000;
}
server {
listen 443 ssl http2;
location /api/ {
proxy_pass http://api_servers;
health_check interval=5 fails=2 passes=2;
}
}
Rate Limiting
http {
# Define zones
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m; # API: 30/min per IP
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; # Login: 5/min per IP
limit_conn_zone $binary_remote_addr zone=conn:10m; # Max connections
server {
# Apply rate limiting
location /api/ {
limit_req zone=api burst=10 nodelay;
limit_conn conn 10; # Max 10 simultaneous connections per IP
limit_req_status 429;
proxy_pass http://nodejs_app;
}
location /api/auth/login {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
proxy_pass http://nodejs_app;
}
# Custom error page for rate limited
error_page 429 /429.json;
location = /429.json {
default_type application/json;
return 429 '{"error":"Too many requests","retryAfter":60}';
}
}
}
Nginx as Static File Server
server {
listen 80;
server_name static.webcoderspeed.com;
root /var/www/static;
# Serve index.html for SPA
location / {
try_files $uri $uri/ /index.html;
}
# Aggressive caching for hashed assets
location ~* \.(js|css|png|jpg|gif|ico|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# No caching for HTML
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store";
}
}
Let's Encrypt SSL (Free)
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate (auto-configures Nginx)
sudo certbot --nginx -d webcoderspeed.com -d www.webcoderspeed.com
# Auto-renewal (already set up by certbot)
sudo certbot renew --dry-run # Test renewal
# Cron for renewal
0 12 * * * /usr/bin/certbot renew --quiet
Nginx Performance Tuning
worker_processes auto; # Match CPU cores
worker_connections 1024; # Max connections per worker
events {
use epoll; # Linux event model (fastest)
multi_accept on; # Accept multiple connections
}
http {
sendfile on; # Efficient file serving
tcp_nopush on; # Send headers in one packet
tcp_nodelay on; # Don't buffer small packets
keepalive_timeout 65;
keepalive_requests 100;
# Buffer sizes
client_body_buffer_size 16k;
client_header_buffer_size 1k;
client_max_body_size 10m;
# Compression
gzip on;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_proxied any;
gzip_types
text/plain
text/css
application/json
application/javascript
application/xml;
# Logging
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
access_log /var/log/nginx/access.log main buffer=16k;
error_log /var/log/nginx/error.log warn;
}
Nginx + Let's Encrypt + Node.js is the classic production stack for Node.js apps. It's battle-tested, free, and handles millions of requests per second.
Advertisement