How to Configure Linux NGINX as a Reverse Proxy with SSL Termination

The Cryptographic Bottleneck

When you host a highly-trafficked web application, performance is everything. If you configure three internal backend web servers (e.g., running Node.js or Apache) to handle the load, you need a load balancer to distribute the traffic evenly. However, if you configure those backend servers to handle HTTPS encryption themselves, they will waste massive amounts of CPU cycles constantly encrypting and decrypting TLS handshakes instead of actually processing database queries or rendering web pages.

The standard architectural solution is SSL Termination. You place a blazing-fast reverse proxy, like NGINX, at the very edge of your network. NGINX holds your company’s private SSL certificate. When a client connects via HTTPS, NGINX intercepts the encrypted traffic, instantly decrypts it (terminating the SSL connection), and forwards the request as raw, unencrypted HTTP traffic to your internal backend servers over the secure local LAN. This offloads 100% of the cryptographic burden to the edge, vastly increasing the speed of your backend servers.

Step 1: Installing NGINX

Deploy NGINX on a dedicated Linux edge server (e.g., Ubuntu/Debian).

sudo apt-get update
sudo apt-get install nginx

Step 2: Preparing the Cryptographic Assets

To terminate SSL, NGINX needs your public certificate and your private key. In a production environment, you typically acquire these from a Certificate Authority like Let’s Encrypt or DigiCert.

For this tutorial, assume you have placed them securely in the standard Linux certificate directories:

  • Public Certificate: /etc/ssl/certs/yourdomain.com.crt
  • Private Key: /etc/ssl/private/yourdomain.com.key

(Ensure the private key is heavily restricted: sudo chmod 600 /etc/ssl/private/yourdomain.com.key)

Step 3: Configuring the Reverse Proxy Block

You must now configure NGINX to listen for encrypted traffic, decrypt it, and route it to your internal backend servers (e.g., 10.0.0.51 and 10.0.0.52).

Create a new configuration file for your site:

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

Input the following configuration:

# Define the upstream backend servers (The internal web servers)
upstream backend_cluster {
    server 10.0.0.51:8080;
    server 10.0.0.52:8080;
}

# The main HTTPS server block
server {
    listen 443 ssl;
    server_name yourdomain.com www.yourdomain.com;

    # Point NGINX to the cryptographic keys
    ssl_certificate /etc/ssl/certs/yourdomain.com.crt;
    ssl_certificate_key /etc/ssl/private/yourdomain.com.key;

    # Enforce modern, secure TLS protocols (Disable TLS 1.0/1.1)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        # Forward the decrypted traffic to the backend cluster
        proxy_pass http://backend_cluster;

        # Inject original client headers so the backend knows the real IP
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_addres_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# Automatically redirect all unencrypted HTTP traffic to HTTPS
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

Step 4: Enabling the Configuration

Save the file and exit the text editor.

You must enable the site by creating a symbolic link to the sites-enabled directory, and then mathematically test the configuration for syntax errors.

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

If the test returns syntax is ok and test is successful, reload the NGINX daemon to apply the changes without dropping active connections:

sudo systemctl reload nginx

The Edge Architecture

Your infrastructure is now highly optimized. When a user in California accesses https://yourdomain.com, they securely negotiate a TLS 1.3 encrypted tunnel directly with the NGINX edge server. NGINX seamlessly handles the heavy cryptography, unwraps the HTTP GET request, and fires it across the internal gigabit LAN to 10.0.0.51 as plain text. The internal server instantly processes the request without spending a single CPU cycle on encryption, returning the data back to NGINX, which re-encrypts it and sends it back to the user in California. You have achieved perfect SSL termination.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.