Journal

nginx as a reverse proxy — from localhost to production with SSL

You have an app running on localhost:3000. You want it accessible at app.yourdomain.com with HTTPS. That's exactly what nginx as a reverse proxy is for.

What is a reverse proxy?

A reverse proxy is a server that sits between the user and your application. The user connects to nginx on port 80/443, and nginx forwards the request to your app running on an internal port.

User → nginx (:443) → app (:3000)

This means:

  • You can run multiple apps under different domains on one server
  • SSL is handled by nginx, not by the app itself
  • Your app doesn't need to be directly exposed to the internet

Installing nginx

# Ubuntu/Debian
sudo apt update && sudo apt install nginx -y

# Check if it's running
sudo systemctl status nginx

Configuration for a single domain

Create a config file:

sudo nano /etc/nginx/sites-available/app.yourdomain.com

Basic configuration:

server {
    listen 80;
    server_name app.yourdomain.com;

    location / {
        proxy_pass http://localhost: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;
    }
}

Enable the config:

sudo ln -s /etc/nginx/sites-available/app.yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

SSL with Certbot

Certbot automatically fetches and renews Let's Encrypt certificates — for free.

# Install
sudo apt install certbot python3-certbot-nginx -y

# Get a certificate (single domain)
sudo certbot --nginx -d app.yourdomain.com

# Multiple subdomains at once
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com -d api.yourdomain.com -d dashboard.yourdomain.com

Certbot automatically modifies the nginx config and adds an HTTP → HTTPS redirect.

Multiple subdomains on one server

Each subdomain is a separate server block in nginx:

# API
server {
    listen 443 ssl;
    server_name api.yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8234;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# Dashboard
server {
    listen 443 ssl;
    server_name dashboard.yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8236;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Auto-renewal of certificates

Certbot certificates expire after 90 days, but certbot sets up a cron job for renewal automatically:

# Check if auto-renewal works
sudo certbot renew --dry-run

Summary

nginx + certbot is the simplest way to expose an app to the world with HTTPS. One server, multiple domains, one wildcard certificate — and everything works. This is the foundation of any production infrastructure.

JOURNAL | nginx as a reverse proxy — from localhost to production with SSL