INFRASTRUCTURE · NETWORKING

Nginx Reverse Proxying & SSL Offloading

In modern web infrastructure, application servers (such as Uvicorn, Node.js, or Puma) are engineered for executing business logic rather than serving static assets, terminating TLS handshakes, or managing rate limits. Positioning Nginx as an edge reverse proxy and SSL offloading gateway provides high availability, security hardening, and performance optimization.

By delegating TLS handshakes, HTTP/2 multiplexing, Gzip/Brotli compression, and static asset caching to Nginx, backend application workers operate with significantly reduced CPU overhead. In this technical guide, we configure a production Nginx gateway featuring TLS 1.3 offloading, upstream load balancing, WebSocket proxying, and security headers.

1. The Role of TLS/SSL Offloading

Cryptographic handshakes (RSA/ECDSA key exchanges and AES-GCM symmetric decryption) consume substantial CPU cycles. In an un-proxied setup, every application worker thread must perform cryptographic decryption for incoming HTTPS packets.

With SSL Offloading (TLS Termination), Nginx handles public HTTPS encryption on port 443, validates certificates, and forwards plain HTTP traffic over isolated, private virtual networks (e.g. http://10.0.1.50:8000) to backend application servers. This concentrates cryptographic processing into Nginx's highly optimized C event-loop workers.

2. Production Nginx Configuration Architecture

Below is a hardened production nginx.conf configuration for riddletech.co.ke, enforcing HTTP/2, TLS 1.3, OCSP stapling, security headers, and upstream load balancing:

# Global worker processes matching CPU cores
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 8192;
    use epoll;
    multi_accept on;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    # Performance Tuning Options
    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens   off;

    # Brotli & Gzip Compression
    gzip on;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    # Rate Limiting Zones (Prevents DDoS and brute-force attacks)
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s;

    # Upstream Backend Server Cluster
    upstream backend_nodes {
        least_conn; # Route traffic to least connected worker
        server 10.0.1.10:8000 max_fails=3 fail_timeout=10s;
        server 10.0.1.11:8000 max_fails=3 fail_timeout=10s;
        keepalive 32; # Keep-alive idle connections to upstream
    }

    # Redirect HTTP to HTTPS automatically
    server {
        listen 80;
        listen [::]:80;
        server_name riddletech.co.ke www.riddletech.co.ke;
        return 301 https://$host$request_uri;
    }

    # Main HTTPS Gateway Server Block
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name riddletech.co.ke www.riddletech.co.ke;

        # SSL Certificate Paths
        ssl_certificate     /etc/letsencrypt/live/riddletech.co.ke/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/riddletech.co.ke/privkey.pem;

        # Hardened TLS Protocols & Ciphers (TLS 1.2 and TLS 1.3 only)
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1d;
        ssl_session_tickets off;

        # OCSP Stapling for fast TLS handshakes
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 1.1.1.1 8.8.8.8 valid=300s;

        # Security Headers (OWASP Recommendations)
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

        # Root Static Directory
        root /var/www/riddletech.web;
        index index.html;

        # Reverse Proxy Location for Dynamic API Traffic
        location /api/ {
            limit_req zone=api_limit burst=20 nodelay;
            
            proxy_pass http://backend_nodes;
            proxy_http_version 1.1;

            # Forward real client connection metadata
            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;

            # Timeouts
            proxy_connect_timeout 5s;
            proxy_read_timeout 60s;
            proxy_send_timeout 60s;
        }

        # WebSocket Proxy Support
        location /ws/ {
            proxy_pass http://backend_nodes;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
        }
    }
}

3. Configuring WebSocket Upgrades

Unlike standard HTTP requests that terminate after receiving a response, WebSocket connections maintain persistent full-duplex TCP streams. To proxy WebSockets through Nginx without premature disconnection, explicitly set the Upgrade and Connection HTTP headers as shown in the location block above.

4. Upstream Health Checks & Load Balancing

Nginx provides built-in passive health checks for upstream server pools using the max_fails and fail_timeout directives. If an upstream app node fails 3 consecutive health checks within 10 seconds, Nginx automatically ejects that server node from the pool until it recovers, eliminating single points of failure.

Conclusion

Configuring Nginx as an edge reverse proxy and TLS offloading gateway delivers dramatic performance, security, and stability benefits. With TLS 1.3 enabled, OCSP stapling active, and robust upstream health checks configured, backend services can scale seamlessly under heavy production workloads.