Proxies·5 min read·

High-Performance Caddy 2 Reverse Proxy with Rate Limiting and Dynamic Upstreams

Configure Caddy 2 as a zero-maintenance reverse proxy with automatic TLS, active health checking, and IP-based rate limiting on a Linux VPS.

NB

Netbay Engineering

Netbay Engineering

On this page

Caddy 2 has become one of the most popular modern reverse proxies due to its memory safety (written in Go), automatic HTTPS issuance via Let's Encrypt and ZeroSSL, and concise configuration format. Unlike traditional web servers that require external cron jobs and certbot scripts, Caddy manages the entire certificate lifecycle natively in-memory, including OCSP stapling and automatic renewals.

For production workloads, pairing Caddy's automatic TLS capabilities with active upstream health checking and IP rate limiting creates a self-healing frontend edge that shields backend applications from traffic bursts.

Caddy's architecture is structured around an internal pluggable JSON model. When you author a human-friendly Caddyfile, Caddy's CLI parser translates that file directly into its native JSON config structure. The server operates with zero global state locks: active HTTP listeners continue serving existing client requests while internal configuration swaps happen atomically. Furthermore, because Caddy handles ACME HTTP-01 and TLS-ALPN-01 challenges internally, there is no need to temporarily disable your reverse proxy or configure complex webroot path routing rules when renewing certificates.

Expand
Caddy 2 Reverse Proxy Setup
High performance Caddy 2 reverse proxy and automatic HTTPS

Writing a Hardened Production Caddyfile

Create /etc/caddy/Caddyfile with rate limiting, response compression, and active health checks:

Caddy 2 Architecture: TLS Auto-Renew & Healthcheck Router Client HTTPS Request TLS 1.3 / HTTP/2 & 3 Port 443 TCP/UDP OCSP stapling automatic Caddy Middleware rate_limit: 100 req/min Header normalization X-Forwarded-For injected Upstream App Pool 127.0.0.1:8080 (Primary) 127.0.0.1:8081 (Replica) Active probe: /healthz Automatic Failover Mechanism: When upstream 8080 fails 2 consecutive /healthz checks, Caddy immediately evicts it from the active routing pool and directs 100% of user traffic to 8081 with zero dropped requests.
caddyfile
{
    email ops@example.com
    admin 127.0.0.1:2019
    log {
        output file /var/log/caddy/access.log {
            roll_size 25mb
            roll_keep 5
        }
        format json
    }
}

api.example.com {
    encode zstd gzip

    # IP rate limiting block
    rate_limit {
        zone dynamic_api {
            key {remote_host}
            events 120
            window 1m
        }
    }

    # Reverse proxy pool with active health checking
    reverse_proxy 127.0.0.1:8080 127.0.0.1:8081 {
        lb_policy round_robin
        lb_try_duration 2s

        health_uri /healthz
        health_interval 5s
        health_timeout 2s
        health_status 200

        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

The reverse_proxy block defines an active health check mechanism. Every 5 seconds, Caddy issues an HTTP GET to /healthz against each configured backend. If upstream 8080 encounters a memory panic or hangs, Caddy fails the health check and immediately redirects 100 percent of client requests to replica 8081. The lb_try_duration 2s directive instructs Caddy to retry failed requests against an alternative healthy upstream rather than returning an immediate 502 error to the user.

Zero-Downtime Configuration Reloads via Admin API

Caddy exposes a local RESTful admin socket at localhost:2019. You can validate and apply configuration updates on the fly without restarting the daemon or terminating existing client connections:

bash
# Format and validate the Caddyfile
caddy fmt --overwrite /etc/caddy/Caddyfile
caddy validate --config /etc/caddy/Caddyfile

# Reload configuration without zero downtime
systemctl reload caddy

# Verify active upstream health states via admin API
curl -s http://127.0.0.1:2019/reverse_proxy/upstreams | jq .

The admin API is especially powerful for automated CI/CD deployment pipelines: a deployment script can dynamically POST an updated JSON configuration to add or remove upstream microservices without restarting Caddy or reloading disk configuration files.

Security Headers and TLS Best Practices

Caddy automatically negotiates TLS 1.3 and TLS 1.2 by default, rejecting vulnerable legacy protocols like SSLv3 and TLS 1.0. Its automatic OCSP stapling eliminates client verification delays during initial handshakes by fetching and caching cryptographically signed revocation proofs directly from Certificate Authorities.

Deploying Caddy delivers enterprise-grade edge proxying with minimal operational maintenance overhead.

Caddy Server Complete Crash Course
YouTube

You can spin up an Ubuntu 24.04 instance on Netbay in under 60 seconds with Intel Xeon Platinum compute and high-speed SSD storage in Lucknow — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance