I often run one Caddy in front of a whole app. It reverse-proxies to the other components, so the Caddyfile belongs in the project.

Development, staging, and production each need their own Caddyfile. Sometimes I need a personal one too, with my own hostnames. They can’t all be named Caddyfile or they collide in git.

I keep a caddy directory at the root of the repo. Git tracks a file per environment. It ignores the plain Caddyfile. On each machine I symlink the right file into place.

text
caddy/
  Caddyfile -> Caddyfile.development
  Caddyfile.development
  Caddyfile.staging
  Caddyfile.production
  Caddyfile.ryan

.gitignore has:

text
caddy/Caddyfile

On a development machine:

sh
cd caddy
ln -sf Caddyfile.development Caddyfile

On production, same command, different target:

sh
ln -sf Caddyfile.production Caddyfile

Caddy always reads Caddyfile. From the project root, the command never changes:

sh
caddy run --config caddy/Caddyfile

Scripts and systemd units point at that same file, so they don’t need to know which environment they’re on. After a clone, make the symlink before you run Caddy.

That’s the whole trick.