Ubuntu & Linux

Nginx Reverse Proxy with SSL: The Complete Setup Guide

Set up Nginx as a reverse proxy with free Let's Encrypt SSL certificates for any web application — Node.js, Python, Go, or Docker containers.

March 18, 20263 min read

What is a Reverse Proxy and Why Do You Need One?

A reverse proxy sits between the internet and your application. Instead of exposing your app directly on port 80/443, Nginx handles all incoming traffic and forwards it to your app running on a local port (like 3000 or 8000).

Benefits:

  • SSL termination — Nginx handles HTTPS so your app doesn't need to
  • Multiple apps, one server — route different domains to different apps
  • Static file serving — Nginx serves static files 10x faster than your app
  • Load balancing — distribute traffic across multiple app instances
  • Security — hide your app's internal port, add rate limiting, block bad requests

Step 1 — Install Nginx

sudo apt update

sudo apt install nginx

# Verify it's running

sudo systemctl status nginx

# Test — visit http://your-server-ip in a browser

curl http://localhost

You should see the "Welcome to nginx" page. If UFW is enabled, allow HTTP/HTTPS:

sudo ufw allow 'Nginx Full'

Step 2 — Configure the Reverse Proxy

Create a configuration file for your domain:

sudo nano /etc/nginx/sites-available/myapp.conf

server {

listen 80;

server_name yourdomain.com www.yourdomain.com;

# Security headers

add_header X-Frame-Options "SAMEORIGIN" always;

add_header X-Content-Type-Options "nosniff" always;

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_set_header X-Forwarded-Proto $scheme;

proxy_cache_bypass $http_upgrade;

}

}

Enable the site and test:

sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/

sudo nginx -t # Test configuration

sudo systemctl reload nginx

Make sure your DNS A record points to your server's IP address.

Step 3 — Add Free SSL with Let's Encrypt

Install Certbot and get a free SSL certificate:

sudo apt install certbot python3-certbot-nginx

# Get certificate (replace with your domain)

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot will:

  • 1. Verify you own the domain
  • 2. Generate the SSL certificate
  • 3. Automatically modify your Nginx config to use HTTPS
  • 4. Set up auto-renewal

Verify auto-renewal works:

sudo certbot renew --dry-run

Certificates auto-renew every 90 days. You never need to touch this again.

Step 4 — Optimize for Production

Add these optimizations to your Nginx config:

server {

listen 443 ssl http2;

server_name yourdomain.com;

# SSL config (added by Certbot)

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

# Gzip compression

gzip on;

gzip_types text/plain text/css application/json application/javascript text/xml;

gzip_min_length 1000;

# File upload size (increase for file conversion tools)

client_max_body_size 200M;

# Timeouts for long-running conversions

proxy_connect_timeout 60s;

proxy_send_timeout 120s;

proxy_read_timeout 120s;

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;

}

# Cache static assets

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {

proxy_pass http://127.0.0.1:3000;

expires 30d;

add_header Cache-Control "public, immutable";

}

}

# Redirect HTTP to HTTPS

server {

listen 80;

server_name yourdomain.com www.yourdomain.com;

return 301 https://$server_name$request_uri;

}

Key settings:

  • client_max_body_size 200M — essential for file upload applications
  • proxy_read_timeout 120s — prevents timeouts on slow conversions
  • Static asset caching — reduces server load significantly

Multiple Apps on One Server

Route different domains to different applications:

# App 1: api.yourdomain.com -> port 8000

server {

server_name api.yourdomain.com;

location / {

proxy_pass http://127.0.0.1:8000;

# ... same proxy headers

}

}

# App 2: yourdomain.com -> port 3000

server {

server_name yourdomain.com;

location / {

proxy_pass http://127.0.0.1:3000;

# ... same proxy headers

}

}

Run sudo certbot --nginx again for each new domain to add SSL. Nginx handles routing based on the Host header — all traffic comes in on port 443, and Nginx sends it to the right app.

nginxreverse proxyssllets encrypthttpsubuntudeployment

Related Articles