Nginx Configuration Cheatsheet: Reverse Proxy and Load Balancing

This comprehensive guide provides essential nginx configurations for setting up reverse proxies, SSL/TLS termination, and load balancing. Whether you’re deploying a single service or managing multiple backend servers, these configurations will help you create secure, efficient nginx setups.

Overview

Nginx is a powerful web server and reverse proxy that excels at handling high-traffic applications. This cheatsheet covers the most common nginx configurations for:

  • Reverse Proxy Setup: Forwarding requests to backend services
  • SSL/TLS Termination: Handling HTTPS connections securely
  • Load Balancing: Distributing traffic across multiple backend servers
  • Security Headers: Implementing modern web security practices
  • WebSocket Support: Enabling real-time communication protocols

Basic Reverse Proxy Configuration

Single Backend Server

The most common nginx use case is proxying requests to a single backend service running on a different port. This configuration includes SSL/TLS termination - for certificate creation and management, see our OpenSSL certificate management guide:

server {
    # Redirect all HTTP requests to HTTPS
    listen 80;
    server_name metrics.lab.net;
    return 301 https://$host$request_uri;
}
 
server {
    # Listen on port 443 for HTTPS connections
    listen 443 ssl;
    server_name metrics.lab.net;
    
    # SSL Certificate and Key
    ssl_certificate /etc/grafana/certs/cert.crt;
    ssl_certificate_key /etc/grafana/certs/cert.key;
    
    # SSL settings (you can customize these as needed)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    # Reverse proxy configuration
    location / {
        proxy_pass http://localhost: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;
    }
    
    # Additional security headers (optional, but recommended)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    add_header X-XSS-Protection "1; mode=block";
}

Key Configuration Elements

HTTP to HTTPS Redirect:

  • The first server block catches all HTTP traffic and redirects it to HTTPS
  • This ensures all connections are encrypted

SSL/TLS Configuration:

  • Supports modern TLS versions (1.2 and 1.3)
  • Uses secure cipher suites
  • Prefers server cipher selection for better security
  • For creating SSL certificates, use OpenSSL commands

Proxy Headers:

  • Host: Preserves the original host header
  • X-Real-IP: Provides the client’s real IP address
  • X-Forwarded-For: Maintains the forwarding chain
  • X-Forwarded-Proto: Indicates the original protocol (HTTP/HTTPS)

Load Balancing Configuration

Multiple Backend Servers

For high-availability applications, nginx can distribute requests across multiple backend servers:

upstream websocket_backend {
    # Define the 8 backend servers (local ports) with round-robin load balancing
    server 127.0.0.1:3333;
    server 127.0.0.1:3334;
    server 127.0.0.1:3335;
    server 127.0.0.1:3336;
    server 127.0.0.1:3337;
    server 127.0.0.1:3338;
    server 127.0.0.1:3339;
    server 127.0.0.1:3340;
    
    # Optionally, you can adjust the weight of each server if needed.
    # server 127.0.0.1:3333 weight=3;  # Example of weighting
}
 
server {
    listen 22000 ssl;
    server_name _;  # Listen on any IP
    
    # SSL Configuration
    ssl_certificate /opt/metric-collector/cert.crt;
    ssl_certificate_key /opt/metric-collector/cert.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    # WebSocket-specific settings
    location / {
        proxy_pass http://websocket_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;
        
        # Optionally, set timeouts to handle WebSocket connections properly
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_connect_timeout 3600s;
    }
}

Load Balancing Methods

Nginx supports several load balancing algorithms:

Round Robin (Default):

upstream backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

Weighted Round Robin:

upstream backend {
    server 127.0.0.1:3000 weight=3;
    server 127.0.0.1:3001 weight=2;
    server 127.0.0.1:3002 weight=1;
}

IP Hash (for session persistence):

upstream backend {
    ip_hash;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

Least Connections:

upstream backend {
    least_conn;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

WebSocket Configuration

WebSocket connections require special handling to maintain the persistent connection:

Essential WebSocket Headers

location /ws {
    proxy_pass http://websocket_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;
    
    # Extended timeouts for WebSocket connections
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
    proxy_connect_timeout 3600s;
}

WebSocket with Load Balancing

For WebSocket applications that need session persistence:

upstream websocket_backend {
    ip_hash;  # Ensures same client connects to same backend
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

SSL/TLS Best Practices

Modern SSL Configuration

server {
    listen 443 ssl http2;
    server_name example.com;
    
    # Certificate configuration
    ssl_certificate /path/to/cert.crt;
    ssl_certificate_key /path/to/cert.key;
    
    # Modern SSL settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    
    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /path/to/chain.crt;
    
    # Session settings
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
}

Security Headers

Implement comprehensive security headers:

# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;

Performance Optimization

Caching Configuration

# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}
 
# API response caching
location /api/ {
    proxy_pass http://backend;
    proxy_cache api_cache;
    proxy_cache_valid 200 302 5m;
    proxy_cache_valid 404 1m;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
}

Connection Optimization

# Connection settings
keepalive_timeout 65;
keepalive_requests 100;
 
# 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 application/xml+rss text/javascript;

Health Checks and Monitoring

Backend Health Monitoring

upstream backend {
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s backup;
}

Status Page Configuration

location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    allow ::1;
    deny all;
}

Common Troubleshooting

Connection Issues

502 Bad Gateway:

  • Check if backend service is running
  • Verify firewall rules
  • Ensure correct upstream configuration

504 Gateway Timeout:

  • Increase proxy timeout values
  • Check backend service performance
  • Verify network connectivity

SSL Issues

SSL Certificate Problems:

  • Verify certificate paths and permissions
  • Check certificate expiration dates using OpenSSL verification commands
  • Ensure proper certificate chain

Mixed Content Warnings:

  • Ensure all resources use HTTPS
  • Check X-Forwarded-Proto header configuration
  • Verify application URL generation

Network Connectivity Issues

Firewall Configuration:

  • Verify firewall rules allow HTTP (80) and HTTPS (443) traffic
  • Use UFW firewall commands to check and configure access
  • Ensure backend services are accessible through firewall rules

Testing Configuration

Syntax Validation

# Test nginx configuration
nginx -t
 
# Reload configuration
nginx -s reload
 
# Check nginx status
systemctl status nginx

Connection Testing

# Test HTTP to HTTPS redirect
curl -I http://example.com
 
# Test SSL configuration
curl -I https://example.com
 
# Test SSL certificate details (requires OpenSSL)
openssl s_client -connect example.com:443 -servername example.com
 
# Test WebSocket connection
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: test" https://example.com/ws

For comprehensive SSL testing and certificate verification, see OpenSSL testing commands.

Questions Answered in This Document

Q: How do I configure nginx as a reverse proxy with SSL termination? A: Use a server block listening on port 443 with SSL certificates, proxy_pass to your backend service, and include proper proxy headers like Host, X-Real-IP, and X-Forwarded-For.

Q: What’s the difference between round-robin and IP hash load balancing? A: Round-robin distributes requests evenly across all backend servers, while IP hash ensures requests from the same client always go to the same backend server, enabling session persistence.

Q: How do I configure nginx for WebSocket connections? A: Set proxy_http_version to 1.1, include Upgrade and Connection headers, and configure extended timeouts (proxy_read_timeout, proxy_send_timeout, proxy_connect_timeout).

Q: What security headers should I include in my nginx configuration? A: Include Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy, and Content-Security-Policy headers for comprehensive security.

Q: How do I handle SSL certificate configuration in nginx? A: Specify ssl_certificate and ssl_certificate_key paths, use modern protocols (TLSv1.2 and TLSv1.3), configure secure ciphers, and optionally enable OCSP stapling. Use OpenSSL commands to create and manage certificates.

Q: What’s the proper way to redirect HTTP to HTTPS in nginx? A: Create a server block listening on port 80 with a return 301 redirect to the HTTPS version using return 301 https://$host$request_uri;.

Q: How do I configure health checks for backend servers? A: Use max_fails and fail_timeout parameters in the upstream configuration to define failure thresholds and recovery time.

Q: What are the essential proxy headers for reverse proxy configuration? A: Include Host (preserves original host), X-Real-IP (client’s real IP), X-Forwarded-For (forwarding chain), and X-Forwarded-Proto (original protocol).

Q: How do I optimize nginx performance for high-traffic applications? A: Enable gzip compression, configure appropriate keepalive settings, implement caching strategies, and use connection pooling with upstream servers.

Q: What’s the correct way to test nginx configuration changes? A: Use nginx -t to validate syntax, nginx -s reload to apply changes, and test with curl commands to verify functionality.

Q: How should I secure my nginx deployment at the network level? A: Combine nginx configurations with proper firewall rules to allow only necessary ports (80, 443, SSH) and restrict access to backend services by IP ranges.