Back to blog

How to Configure Nginx as a Reverse Proxy with SSL/TLS Let us Encrypt

When deploying web applications to production, running your application server (such as Node.js, Go, or Python) directly exposed to the public internet is a security and performance bottleneck. Application servers are not designed to handle massive concurrent requests, slow clients, or SSL/TLS handshakes efficiently.

The standard architecture is placing Nginx in front of your application as a Reverse Proxy. Nginx intercepts incoming public traffic, acts as a security buffer, serves static assets directly, and forwards clean requests to your application server.

In this guide, we will configure Nginx as a reverse proxy, set up proxy headers, and secure it with free, auto-renewing SSL certificates using Let us Encrypt.

Why Use Nginx as a Reverse Proxy?

  • SSL/TLS Termination: Nginx handles the CPU-heavy encryption/decryption layer, allowing your backend application to run over plain HTTP on localhost, saving processing resources.
  • Security Shielding: Nginx hides the identity and structure of your backend server, shielding it from direct port attacks.
  • Static File Caching: Nginx can serve static images, CSS, and JS files directly from disk without touching your backend server, freeing up your app thread.
  • Load Balancing: If your app grows, Nginx can distribute incoming traffic across multiple instances of your application.

Step 1: Install Nginx

On Debian or Ubuntu servers:

sudo apt update
sudo apt install nginx

Once installed, Nginx starts automatically. Verify that it is running:

sudo systemctl status nginx

Step 2: Configure the Reverse Proxy

Create a new configuration file for your domain in the sites-available directory:

sudo nano /etc/nginx/sites-available/example.com

Paste the following server configuration. This setup assumes your backend application runs on localhost port 3000:

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        
        # Enable WebSockets support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        
        # Forward original client IP and host details
        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;

        # Disable response buffering for streaming APIs (optional)
        proxy_buffering off;
    }

    # Static files caching block
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

Enable this site by creating a symbolic link to the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Validate your Nginx configuration syntax:

sudo nginx -t

If it reports success, restart Nginx to apply changes:

sudo systemctl restart nginx

Step 3: Secure the Proxy with Let us Encrypt SSL

We will use Certbot, the official client tool for Let us Encrypt, to acquire a free SSL/TLS certificate.

First, install Certbot and its Nginx plugin:

sudo apt install certbot python3-certbot-nginx

Run Certbot to request a certificate. Certbot automatically inspects your Nginx configurations, requests the certificate for your domain, and modifies your Nginx configuration to enable SSL:

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

During the prompt, select the option to automatically redirect all HTTP traffic to HTTPS.

Certbot configures a cron job to automatically renew your certificates before they expire, ensuring your site remains secure indefinitely.

Testing Auto-Renewal

To test the automated renewal process without making actual certificate requests, run:

sudo certbot renew --dry-run

If the dry run succeeds, your setup is complete. Nginx will automatically reload renewed certificates in the background.

Conclusion

Placing Nginx in front of your backend application server is a production deployment best practice. By offloading SSL termination, handling WebSocket upgrades, and caching static resources, Nginx improves both the security and speed of your backend services, allowing your code to focus entirely on executing dynamic business logic.