DEV Community

Arnob
Arnob

Posted on

Configure SSL Passthrough in NGINX Stream

captionless image

SSL Passthrough allows encrypted HTTPS/TLS traffic to pass through a proxy or load balancer without decrypting it.

Instead of terminating SSL at NGINX, the encrypted connection is forwarded directly to the backend server.

SSL Passthrough, NGINX cannot inspect:

  • URLs
  • Headers
  • Cookies
  • HTTP paths

Because traffic remains encrypted.

Simple rule:

πŸ”Ή SSL Termination β†’ NGINX decrypts traffic
πŸ”Ή SSL Passthrough β†’ Backend decrypts traffic

Architecture

Client HTTPS
     |
     v
NGINX Stream
     |
     v
Backend HTTPS Server
Enter fullscreen mode Exit fullscreen mode

Backend server handles:

  • SSL certificates
  • TLS handshake
  • Decryption

Step 1: Enable Stream Module

Ubuntu/Debian

Install:

sudo apt install libnginx-mod-stream
Enter fullscreen mode Exit fullscreen mode

Check:

nginx -V 2>&1 | grep stream
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure Stream Block

Edit:

/etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

Add:

stream {
    upstream https_backend {
        server 10.0.0.20:443;
    }
    server {
        listen 443;
        proxy_pass https_backend;
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Reload NGINX

sudo nginx -t
sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

Step 4: Backend HTTPS Server

Backend server MUST already have:

  • SSL certificate
  • HTTPS enabled

Example backend:

Apache / NGINX / Kubernetes Ingress
Enter fullscreen mode Exit fullscreen mode

NGINX Stream does NOT terminate SSL.

How It Works

Client connects:

https://example.com
Enter fullscreen mode Exit fullscreen mode

NGINX Stream:

  • Accepts TCP connection
  • Forwards encrypted packets

Backend:

  • Performs TLS handshake
  • Decrypts traffic

SNI-Based SSL Passthrough (Multiple Domains)

You can route by SNI hostname.

Example:

stream {
    map $ssl_preread_server_name $backend_name {
        app1.example.com app1;
        app2.example.com app2;
    }
    upstream app1 {
        server 10.0.0.11:443;
    }
    upstream app2 {
        server 10.0.0.12:443;
    }
    server {
        listen 443;
        proxy_pass $backend_name;
        ssl_preread on;
    }
}
Enter fullscreen mode Exit fullscreen mode

What is ssl_preread?

NGINX reads:

  • TLS SNI hostname

WITHOUT decrypting SSL.

Used for:

  • Multi-domain passthrough
  • Kubernetes ingress passthrough

Kubernetes Example

Used in:

  • NGINX Ingress Controller
  • TCP ingress
  • TLS passthrough

Architecture:

Internet
   |
Load Balancer
   |
NGINX Stream
   |
Kubernetes Service
Enter fullscreen mode Exit fullscreen mode

Important Limitations

With SSL Passthrough, NGINX cannot:

  • Read URL paths
  • Inspect headers
  • Use WAF rules
  • Cache HTTP
  • Modify requests

Because traffic stays encrypted.

SSL Termination vs Passthrough

| Feature                | SSL Termination | SSL Passthrough |
| ---------------------- | --------------- | --------------- |
| SSL decrypted at NGINX | Yes             | No              |
| Backend sees HTTP      | Yes             | No              |
| End-to-end encryption  | No              | Yes             |
| URL routing            | Yes             | No              |
| WAF possible           | Yes             | No              |
Enter fullscreen mode Exit fullscreen mode

Real Production Use Cases

Banking Systems

Strict end-to-end TLS.

Kubernetes

TLS passthrough ingress.

Database TLS

Secure PostgreSQL/MySQL traffic.

Multi-Tenant Platforms

SNI hostname routing.

SSL Passthrough means:

NGINX forwards encrypted traffic
Backend decrypts it
Enter fullscreen mode Exit fullscreen mode

Best when you need:

  • End-to-end encryption
  • TCP/TLS proxying
  • Kubernetes passthrough
  • Secure internal infrastructure

In NGINX Stream, SSL certificates can be configured in two different ways, depending on whether you use:

  1. SSL Termination
  2. SSL Passthrough

1. SSL Passthrough (No Certificate in NGINX)

In SSL Passthrough:

Client --> NGINX Stream --> Backend HTTPS Server
Enter fullscreen mode Exit fullscreen mode

NGINX does NOT decrypt traffic.

So:

  • NO SSL certificate needed in NGINX
  • Certificate stays on the backend server

Example:

stream {
    upstream backend {
        server 10.0.0.20:443;
    }
    server {
        listen 443;
        proxy_pass backend;
    }
}
Enter fullscreen mode Exit fullscreen mode

Certificate is configured on:

  • Apache
  • Backend NGINX
  • Kubernetes ingress
  • Application server

2. SSL Termination in NGINX Stream

Here, NGINX decrypts TLS traffic.

Architecture:

Client HTTPS
      |
      v
NGINX Stream (SSL Termination)
      |
      v
Backend TCP/HTTP
Enter fullscreen mode Exit fullscreen mode

Now you MUST configure:

  • SSL certificate
  • Private key

inside NGINX Stream.

Stream SSL Configuration

Example:

stream {
    upstream backend {
        server 10.0.0.20:443;
    }
    server {
        listen 443 ssl;
        proxy_pass backend;
        ssl_certificate     /etc/nginx/ssl/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/private.key;
    }
}
Enter fullscreen mode Exit fullscreen mode

SSL Files

Usually:

/etc/nginx/ssl/fullchain.pem
/etc/nginx/ssl/private.key
Enter fullscreen mode Exit fullscreen mode

Using Let’s Encrypt

With Let’s Encrypt:

sudo certbot certonly
Enter fullscreen mode Exit fullscreen mode

Certificates are usually stored in:

/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pem
Enter fullscreen mode Exit fullscreen mode

Example with Let’s Encrypt

stream {
    upstream app {
        server 10.0.0.20:8443;
    }
    server {
        listen 443 ssl;
        proxy_pass app;
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    }
}
Enter fullscreen mode Exit fullscreen mode

Enable TLS Versions

Example:

ssl_protocols TLSv1.2 TLSv1.3;
Enter fullscreen mode Exit fullscreen mode

Configure Strong Ciphers

Example:

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
Enter fullscreen mode Exit fullscreen mode

Full Production Example

stream {
    upstream postgres_ssl {
        server 10.0.0.11:5432;
        server 10.0.0.12:5432;
    }
    server {
        listen 5432 ssl;
        proxy_pass postgres_ssl;
        ssl_certificate /etc/nginx/ssl/postgres.pem;
        ssl_certificate_key /etc/nginx/ssl/postgres.key;
        ssl_protocols TLSv1.2 TLSv1.3;
    }
}
Enter fullscreen mode Exit fullscreen mode

Test Configuration

sudo nginx -t
Enter fullscreen mode Exit fullscreen mode

Reload:

sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

Verify SSL

Test with OpenSSL:

openssl s_client -connect example.com:443
Enter fullscreen mode Exit fullscreen mode

Important Difference

| Mode            | SSL Certificate Location |
| --------------- | ------------------------ |
| SSL Passthrough | Backend Server           |
| SSL Termination | NGINX Stream             |
Enter fullscreen mode Exit fullscreen mode

Real Use Cases

SSL Passthrough

Used when:

  • End-to-end encryption required
  • Kubernetes ingress passthrough
  • Banking systems

SSL Termination

Used when:

  • Centralized certificate management
  • Load balancing HTTPS
  • SSL offloading

Passthrough

NGINX forwards encrypted traffic
Backend handles SSL
Enter fullscreen mode Exit fullscreen mode

Termination

NGINX decrypts SSL
NGINX needs certificate
Enter fullscreen mode Exit fullscreen mode

Summary

Configuring SSL in NGINX Stream. NGINX Stream supports SSL in two ways:

SSL Passthrough

NGINX forwards encrypted traffic directly to the backend.

Client β†’ NGINX Stream β†’ Backend HTTPS Server
Enter fullscreen mode Exit fullscreen mode

βœ… End-to-end encryption
βœ… Backend manages SSL certificates
❌ NGINX cannot inspect HTTP traffic

SSL Termination

NGINX decrypts SSL traffic and requires certificates configured locally.

Client β†’ NGINX Stream (SSL) β†’ Backend Server
Enter fullscreen mode Exit fullscreen mode

Example:

server {
    listen 443 ssl;
    proxy_pass backend;
    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/private.key;
}
Enter fullscreen mode Exit fullscreen mode

Key Difference

πŸ”Ή SSL Passthrough β†’ Certificate on Backend
πŸ”Ή SSL Termination β†’ Certificate on NGINX

Commonly used for:

  • Kubernetes
  • PostgreSQL/MySQL TLS
  • Load Balancing
  • Secure Infrastructure
  • High Availability Systems

Top comments (0)