codingstairs
NotesEDULifeContact
⌕Search⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

Get in touch

Send without signing in. Add your email if you'd like a reply.

  • Leave a message anonymously →
  • ✉ warragon112@gmail.com
  • KakaoTalk Open Chat ↗

© 2026 codingstairs

  • Notes
  • EDU
  • Search
  • Life
  • Contact
  • Legal
  • RSS
  • GitHub
Notes›infra

Caddy and nginx — A Comparison

Published 2026-04-28· Updated 2026-05-18·0 views

Caddy and nginx — A Comparison

Reverse proxy, HTTPS termination, and static file serving show up in nearly every web service. nginx has been the long-standing standard, and Caddy carved out its place by emphasizing automatic HTTPS and simple configuration. This piece covers the origins of both tools, what automatic HTTPS means, syntax differences, neighboring tools (traefik, HAProxy), and the distinction between reverse proxy and load balancer.

1. About the Two Tools

Tool First release Note
nginx 2004, Igor Sysoev Written in C. Event-driven. Acquired by F5 in 2019.
HAProxy 2001 (1.0), Willy Tarreau Written in C. Started as an L4 / L7 load balancer.
Caddy 2015, Matt Holt Written in Go. Major redesign in v2 (2020). Automatic HTTPS as a first-class feature.
traefik 2015, Containous (now Traefik Labs) Written in Go. Dynamic configuration based on container labels and service discovery.

The foundation of automatic HTTPS — the ACME protocol (RFC 8555, 2019) and Let's Encrypt (in production from 2016). Before 2016, certificate issuance and renewal were manual.

2. Caddy's Automatic HTTPS

Just write a domain in the Caddyfile and Caddy issues and renews the certificate as an ACME client. It auto-handles HTTP-01 or TLS-ALPN-01 challenges.

example.com {
    reverse_proxy 127.0.0.1:8080
}

This one line handles 80 → 443 redirects, certificate issuance, the renewal schedule, and HTTPS termination. Doing the same with nginx requires certbot, a renewal cron, and two server blocks (80 and 443).

3. Caddyfile vs nginx.conf

# Caddyfile
api.example.com {
    reverse_proxy /v1/* 127.0.0.1:8080
    encode zstd gzip
    log
}
# nginx.conf
server {
    listen 443 ssl http2;
    server_name api.example.com;
    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location /v1/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    gzip on;
    access_log /var/log/nginx/access.log;
}

nginx allows more explicit and fine-grained control. Caddy comes with strong sensible defaults (Host header, X-Forwarded-For auto-set, and so on).

4. nginx's Strengths

  • A huge pool of operations cases and tutorials.
  • Very fine-grained modules and directives.
  • A wide range of third-party modules (extensions like OpenResty).
  • Powerful L7 caching (proxy_cache).

5. Caddy's Strengths

  • Automatic HTTPS as the standard.
  • Single binary (Go), simple to start.
  • Dynamic configuration through a JSON API.
  • Module system (plug-ins) that adds features at build time.

6. traefik's place

In container environments (Docker / Compose, Kubernetes) it watches labels and resources to auto-update routes. Discovery-based configuration rather than static files. The common contrast — Caddy for simple proxying on a single host, traefik for dynamic routing in container environments.

7. Reverse Proxy vs Load Balancer

Concept Meaning
Reverse proxy Receives client requests, forwards to internal servers, and returns responses. Caching, compression, SSL termination.
Load balancer Distributes requests across multiple backends. L4 (TCP) or L7 (HTTP).

Reverse proxies usually do load balancing too. HAProxy started as a load balancer; nginx and Caddy started as reverse proxies and cover both. Managed cloud services like ELB / ALB / NLB occupy the same place.

8. Caddy Single-host Operation Example

{
    email admin@example.com
}

example.com {
    reverse_proxy 127.0.0.1:3000
}

api.example.com {
    reverse_proxy 127.0.0.1:8080
    @ratelimit {
        path /login
    }
    rate_limit @ratelimit 5r/m   # plugin required
}

static.example.com {
    root * /var/www/static
    file_server
    encode zstd gzip
}

9. nginx Single-host Operation Example

Issue and renew certificates with certbot:

# Linux
sudo certbot --nginx -d example.com
# auto-renew via systemd timer or cron
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

10. Common Pitfalls

Reachability on port 80 — ACME HTTP-01 challenges have to land on 80. Make sure firewalls and cloud security groups open both 80 and 443.

Rate limits and ACME quotas — Let's Encrypt has per-domain issuance limits. Registering wildcard certs or unrelated domains carelessly can trigger blocks.

X-Forwarded-For trust — if the application behind the reverse proxy doesn't trust the header, it sees the proxy IP as the client IP. Caddy sets it automatically; nginx needs explicit configuration.

The slash difference in proxy_pass (nginx) — proxy_pass http://up; and proxy_pass http://up/; differ in URL composition. A frequent cause of production incidents.

HTTP/2 and WebSocket — header forwarding and upgrade handling differ in some environments. Both proxies allow explicit configuration.

Closing thoughts

For small-to-mid single-host operations, Caddy's automatic HTTPS plus sensible defaults provide the biggest value. Unless you genuinely need nginx's deep tuning options (large-scale caching, OpenResty Lua), the path that ends in one Caddyfile line wins on operational cost. That said, nginx's vast pool of operations cases is a separate value of its own.

Next

  • loopback-ssh-tunnel
  • single-server-philosophy

Refer to Caddy, Caddy on GitHub, nginx, traefik, HAProxy, Let's Encrypt, and RFC 8555 ACME.

More in infra

All in this category →
  • Cloud Emulator Stack — Designing a 4th Environment
  • Local HTTPS — mkcert and a Self CA
  • The Place of Single-server Operations
  • Loopback Binding and SSH Tunnel
  • Docker Compose Patterns
  • Docker Basics