Skip to content
Back to Blog
Linux

Nginx as a Reverse Proxy: Load Balancing & SSL Termination

Configure Nginx for reverse proxying, load balancing multiple backends, and SSL termination with Let's Encrypt in production.

Jul 2025
11 min read

Nginx Reverse Proxy with SSL and Load Balancing

Nginx is the most deployed reverse proxy/load balancer. This covers a production-ready setup with Let's Encrypt SSL.

Installation

BASH
apt install nginx certbot python3-certbot-nginx

Basic Reverse Proxy

NGINX
# /etc/nginx/sites-available/app.conf
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/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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_cache_bypass $http_upgrade;
    }
}

Load Balancing Multiple Backends

NGINX
upstream backend {
    least_conn;
    server 10.0.0.10:3000 weight=3;
    server 10.0.0.11:3000 weight=2;
    server 10.0.0.12:3000 weight=1 backup;
    keepalive 32;
}

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

    location / {
        proxy_pass http://backend;
        proxy_next_upstream error timeout;
        health_check interval=10 fails=3 passes=2;
    }
}

Rate Limiting

NGINX
# /etc/nginx/nginx.conf
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn:10m;

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_conn conn 10;
        }
    }
}

Let's Encrypt Certificate

BASH
certbot --nginx -d app.example.com -d www.app.example.com
# Auto-renewal via systemd timer (enabled by default)
certbot renew --dry-run

Security Headers

NGINX
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";