web / caddy

When I run a web service on a VM, I use Caddy as a reverse proxy to terminate TLS in front of the app.

Config

The config for a service:

# /etc/caddy/Caddyfile
cibot.example.com {
  reverse_proxy 127.0.0.1:1994
}

Point DNS at the box and reload:

sudo cp Caddyfile /etc/caddy/Caddyfile
sudo systemctl reload caddy

The app listens on localhost. Caddy terminates HTTPS and renews a Let's Encrypt certificate.

Compared to a PaaS

A PaaS like Render provisions certificates and terminates HTTPS at a shared edge with DDoS protection. Caddy gives me the same certificates on a VM. I lose the edge and gain control and a flat cost.

Caddy vs nginx

Both are fast enough at my scale. Caddy renews certificates by default. nginx needs certbot and a renewal timer. Caddy is a single Go binary, like everything else I deploy.

Caddy vs an app server

Caddy runs in front of an application server such as Puma:

client --HTTPS--> Caddy (:443, TLS) --HTTP--> app (127.0.0.1)

Puma runs the Rack app. Caddy fronts any localhost listener, in Go, Ruby, or another language.

CAA records

If certificate issuance fails, check the domain's CAA records. They restrict which authorities can issue certificates. If the apex excludes Let's Encrypt, add a record for the subdomain:

cibot  CAA  0 issue "letsencrypt.org"

A subdomain inherits CAA records until a closer record exists. This record overrides the apex policy for that host.

← All articles