Skip to main content

Reverse Proxy (Nginx, Caddy, Traefik)

An intermediary server architectural layer that accepts external internet traffic (ports 80/443), performs SSL/TLS termination, compression (Brotli/Gzip), static caching, and securely routes requests to internal applications.

1. Concept Overview & Systemic Problem

Beginner developers often attempt to expose their server directly to the internet by running npm start or uvicorn main:app on port 80. Such a configuration is a gross violation of production architectural standards:

  • Security: Listening on ports 80 and 443 requires the process to run with superuser privileges (root). Any vulnerability in an npm dependency gives an attacker full control over the operating system.
  • Slowloris Attacks: A client with a poor connection that sends one byte every 10 seconds can block the Node.js or Python event loop, paralyzing service for other users.
  • Inefficient Static Serving: Serving images, fonts, and JS files through application worker threads consumes resources that should be allocated to business logic.
  • Fragility of SSL: The need to configure encryption within the application code necessitates service restarts with every certificate update.

Reverse Proxy serves as the secure gateway to your infrastructure. It accepts external internet traffic, decrypts HTTPS connections, compresses data, caches static files, and transparently forwards clean internal traffic to the local ports of your isolated applications (127.0.0.1:3000).

2. Architectural Taxonomy & Mental Model

The architectural landscape of reverse proxies is classified by configuration paradigms:

┌─────────────────────────────────────────────────────────────┐
│                 REVERSE PROXY COMPARISON MATRIX             │
├─────────────────────────────────────────────────────────────┤
│ 1. Nginx: Event-driven C architecture (epoll / kqueue)      │
│    • Maximum raw performance, minimal memory usage           │
│    • Requires external Certbot for Let's Encrypt             │
├─────────────────────────────────────────────────────────────┤
│ 2. Caddy: Memory-safe Go Server with Auto-HTTPS (ACME)      │
│    • Native automatic acquisition and rotation of SSL        │
│    • Modern concise syntax (Caddyfile)                       │
│    • Native support for HTTP/3 (QUIC) out of the box        │
├─────────────────────────────────────────────────────────────┤
│ 3. Traefik: Cloud-Native Container Router                    │
│    • Dynamic service discovery via Docker Labels             │
│    • Ideal for PaaS automation (Coolify, Kubernetes)        │
└─────────────────────────────────────────────────────────────┘
  1. TLS/SSL Termination:
    • The proxy handles resource-intensive cryptographic operations (TLS Handshake), relieving the backend from load.
  2. Virtual Hosting & Routing:
    • Allows hosting multiple projects on a single server with one IP address:
      • gotburnout.com ➔ local container on port 3000 (Next.js).
      • api.gotburnout.com ➔ local container on port 8000 (FastAPI).
      • n8n.gotburnout.com ➔ internal port 5678 (n8n).
  3. WebSockets & SSE Proxying:
    • Special handling of Upgrade headers and disabling buffering to support full-duplex connections and token streaming from LLMs.
  4. On-the-fly Compression (Gzip & Brotli):
    • Compresses text resources, reducing the volume of traffic sent to the client by 60–80%.

3. Technical Pipeline & Internal Mechanics

The lifecycle of a client request passing through a reverse proxy:

  1. Establishing a Secure Connection (TLS Handshake): The client initiates a connection on port 443. Caddy or Nginx negotiates TLS 1.3, sends a valid domain certificate, and encrypts the channel.
  2. Header and SNI Analysis (Server Name Indication): The proxy reads the Host: gotburnout.com header and the URL path /api/v1/chat.
  3. Proxy Header Normalization: The proxy adds service headers so the internal application knows the real client IP address:
    X-Real-IP: 203.0.113.195
    X-Forwarded-For: 203.0.113.195, 10.0.0.1
    X-Forwarded-Proto: https
    
  4. Upstream Dispatch: The request is redirected to the local socket http://127.0.0.1:3000 through a pre-opened connection pool.
  5. Receiving and Forwarding the Response to the Client:
    • If a static file is returned — the proxy caches it.
    • If it is token streaming (SSE) — the proxy immediately streams each chunk to the client without buffering.

4. Production Engineering Scenarios

01. Configuring Caddy for Next.js and AI Streaming in 10 Lines

A Caddyfile for production with automatic HTTPS and streaming support:

gotburnout.com {
    encode zstd gzip

    # Proxying the application
    reverse_proxy 127.0.0.1:3000 {
        # Disabling buffering for instant LLM token streaming
        flush_interval -1
    }

    # Caching Next.js static files for 1 year
    @static path /_next/static/*
    header @static Cache-Control "public, max-age=31536000, immutable"
}

02. Nginx Configuration for Server-Sent Events (SSE)

Preventing streaming hangs in Nginx:

location /api/generate {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Connection '';
    
    # Critical directives for AI streaming:
    proxy_buffering off;
    proxy_cache off;
    chunked_transfer_encoding on;
    proxy_read_timeout 600s;
}

03. Routing a Multi-Service Platform on a Single Server

Organizing access to internal tools:

  • Caddy distributes traffic: requests to ai.company.internal are routed to the Ollama container, while metrics.company.internal goes to the Grafana dashboard, securing access with basic authorization (basic_auth).

5. Pitfalls, Common Mistakes & Security

  • Streaming hangs due to buffering: The most common mistake in Nginx is having proxy_buffering enabled by default. Users see a blank screen for 30 seconds, after which the entire generated article appears at once.
  • IP Spoofing through unreliable headers: If your backend naively reads req.headers['x-forwarded-for'] without verifying that the request came from your local proxy, an attacker can spoof any IP address to bypass rate limits.
  • Host Header Injection: If the Nginx configuration has a default block (default_server) that forwards traffic without checking the host name, an attacker can manipulate password reset links through a forged Host header.
  • Forgotten timeouts for long AI requests: The standard timeout for waiting for a response from the backend is 60 seconds (proxy_read_timeout 60s). If a complex reasoning model takes 90 seconds, the proxy will return a 504 Gateway Timeout to the client. Increase the timeout for AI routes.
/ Frequently Asked QuestionsSchema.org FAQPage

FAQ: Reverse Proxy (Nginx, Caddy, Traefik)

Binding to privileged ports (80/443) requires running the application as root (a critical security risk). Node.js applications are poorly optimized for slow connections (Slowloris attacks), serving heavy static files through V8 blocks the event loop, and process crashes completely halt site access.
/ Internal links
All terms