Server Setups/Getting started
Terminate TLS with Caddy in front of Node
Automatic HTTPS, HTTP/3 and sane security headers in a twelve-line Caddyfile — no certbot cron jobs.
beginner15 min
// read first
On this page
Caddy exists to make this boring. It obtains and renews certificates by itself, defaults to sensible TLS settings, and its config file is short enough to read in full.
I have run nginx with certbot for years and there is nothing wrong with it. There is simply no longer a reason to, for a single-host setup.
Install
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddyFROM caddy:2-alpine
COPY Caddyfile /etc/caddy/Caddyfile
EXPOSE 80 443 443/udpThe Caddyfile
This is a complete production config. The encode line matters more than it looks — without it you are shipping uncompressed HTML.
example.com, www.example.com {
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
handle_path /static/* {
root * /home/deploy/app/public
file_server
header Cache-Control "public, max-age=31536000, immutable"
}
reverse_proxy 127.0.0.1:3000
}Verify
sudo caddy validate --config /etc/caddy/Caddyfile— catches syntax errors before a reload.sudo systemctl reload caddy— reloads without dropping connections.curl -sI https://example.com | head -20— confirm a 200 and the HSTS header.journalctl -u caddy -f— watch the certificate being issued.
Common failures
| Symptom | Cause | Fix |
|---|---|---|
| Cert never issues | Port 80 blocked | ufw allow 80/tcp — ACME needs it |
| 502 from Caddy | App not listening on 127.0.0.1 | Bind to loopback, not 0.0.0.0 |
| Stale assets | Immutable cache on hashed files only | Only set immutable on fingerprinted paths |