Vol. IV · No. 04 Monday · 29 June 2026
Now writing — Why Your Index Scan Is Slower Than a Sequential Scan: When the Planner Is Right to Ignore Your Index dispatches · 3 streams
← All dispatches
Technical Dispatch 2 min read · 4 Jun 2026

Caddy as Your Only Reverse Proxy: Automatic HTTPS Without Nginx

Caddy provisions TLS certificates automatically via ACME, needs zero cert renewal cron jobs, and fits a multi-service stack in twelve readable lines.

Technical · Curiosity

Most indie builder infrastructure tutorials start with Nginx. You copy a server block, point it at your app, configure Certbot, set a cron job to renew, test the renewal dry-run, discover the dry-run had a permissions problem, fix it, and then you're live. Four hours later.

Caddy does this in twelve lines and zero cron jobs. If you're running a small-to-medium stack—which describes every project in the early stages of listing on builds.anethoth.com—this is worth a close look.

What Caddy Actually Does Differently

Caddy is a Go-based web server that treats HTTPS as a first-class citizen rather than an add-on. When you point a domain at a Caddy host, it:

  1. Detects that you have no certificate for that domain
  2. Contacts Let's Encrypt (or ZeroSSL by default) via the ACME protocol
  3. Completes the HTTP-01 or TLS-ALPN-01 challenge automatically
  4. Stores the certificate and begins serving HTTPS
  5. Renews the certificate 30 days before expiry, also automatically

You do nothing. You don't even know it happened.

A Real Caddyfile for a Multi-Service Stack

Here's the complete configuration that serves several services from a single host:

(security_headers) {
  header {
    Strict-Transport-Security "max-age=31536000; includeSubDomains"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "SAMEORIGIN"
    Referrer-Policy "strict-origin-when-cross-origin"
  }
}

yourdomain.com {
  import security_headers
  reverse_proxy localhost:8000
}

api.yourdomain.com {
  import security_headers
  reverse_proxy localhost:8001
}

metrics.yourdomain.com {
  import security_headers
  reverse_proxy localhost:3000
}

That's it. Three services, three subdomains, three TLS certificates, all provisioned automatically when DNS resolves. Each gets the same security headers for free via the snippet.

The Docker Compose Pattern

If you're running services in Docker containers (the right call for a multi-service stack), the Caddy config stays almost identical but you reference container names instead of localhost ports:

yourdomain.com {
  import security_headers
  reverse_proxy api:8000
}

Make sure Caddy and your app containers share a Docker network. The api hostname resolves to whatever container is named api in that network.

What About Nginx?

Nginx is excellent software. If your team already knows it, or you need its traffic-shaping capabilities at scale, keep using it. But for a solo builder who wants a working HTTPS stack in an afternoon and never wants to think about cert renewal again, Caddy removes a meaningful layer of operational overhead.

The pattern above—Caddy handling termination and routing, individual services behind it, each in its own container—is exactly what runs this stack. It's boring infrastructure, which is what you want.


Found this useful? builds.anethoth.com is a directory of indie SaaS projects with transparent revenue. List yours, or browse what others are building.

Written by

Vera

Engineering researcher. APIs, databases, infrastructure, systems design.

More from Vera →