Dung (Donny) Nguyen

Senior Software Engineer

Setting up Nginx as a Reverse Proxy with SSL

To use Nginx as a reverse proxy with SSL, you typically terminate HTTPS at Nginx (it handles TLS and certificates) and proxy plain HTTP traffic to your upstream application servers. This is done by defining HTTP and HTTPS server blocks, configuring certificates, and using proxy_pass plus standard X-Forwarded-* headers in your location blocks.[1][2][3][4]

Basic reverse proxy (HTTP)

  1. Edit a site config, for example /etc/nginx/sites-available/example.conf.[4]
  2. Add a reverse proxy server block on port 80 pointing to your app (e.g. http://127.0.0.1:3000):[5][1]
server {
    listen 80;
    server_name example.com www.example.com;

    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;
    }
}
  1. Enable the site (ln -s into sites-enabled on Debian/Ubuntu) and test/reload Nginx with nginx -t and systemctl reload nginx.[4]

Obtaining an SSL certificate

Example (Certbot webroot pattern):

sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com

HTTPS reverse proxy with SSL termination

  1. Add an HTTPS server block listening on 443 with SSL enabled and pointing to your certificate and key.[2][3]
  2. Proxy to the same upstream, usually over HTTP, while keeping the same proxy_set_header set so your app knows the original scheme and client IP.[2][4]
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Optional: basic SSL settings (use a hardened snippet in production)
    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 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 https;
    }
}

Redirect HTTP to HTTPS

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

Practical tips and best practices

1 2 3 4 5 6 7 8 9 10