Operate Caddy
Reload without downtime
Validate a changed Caddyfile, reload through the admin API, and verify behavior before accepting the change.
Configuration changes shouldn’t drop requests. Caddy is built around graceful reloads: it loads the new configuration, starts serving with it, and lets in-flight requests finish on the old one. Zero downtime, if you follow a safe sequence.
The four-step sequence
This is the sequence I use every time:
caddy fmt --overwrite Caddyfile
caddy validate --config Caddyfile
caddy reload --config Caddyfile
curl -f https://app.example.com/health
Format, validate, reload, verify. Let’s see why each step earns its place.
Validate before the server sees it
caddy validate catches a broken configuration on your terminal, before the running server ever sees it. If validation fails, you just fixed a production incident that never happened.
Reload through the admin API
caddy reload sends the new configuration to the running Caddy through its admin API, a local HTTP endpoint on localhost:2019. The server applies it gracefully. Listeners stay open and existing connections finish.
And if the new config fails to load, Caddy keeps running the old one and the command prints the error. A bad reload gets you an error message, not an outage.
Verify the behavior
The final curl -f checks behavior. A valid config is not the same as a correct config. You can validly route all traffic to the wrong upstream, and validation will be happy.
So hit a health endpoint and confirm the site does what you meant. The -f flag makes curl exit non-zero on HTTP errors, so the same line works in a deploy script and stops it when something is off.
Keep a way back
Keep the previous known-good Caddyfile until that last check passes. Version control makes this free. Roll back by checking out the old file and running the same four commands.
Don’t restart for config changes
What you should not do is systemctl restart caddy for routine changes. A restart kills connections mid-flight. Reload exists so you never have to. Save restarts for one job: upgrading the Caddy binary itself.
Did you actually reload?
And the day-one mistake, one more time, because it costs people real debugging hours. Editing the Caddyfile changes nothing on its own. Caddy doesn’t watch files.
When the behavior doesn’t match the file, ask yourself one question first: did I reload? Nine times out of ten, that’s the whole bug.
Try this on your own: introduce a typo in a directive name, then run the four commands. Validation fails. Run the reload anyway and Caddy rejects the config too, while the site keeps working on the old one. That’s the safety net doing its job, twice.
Lesson completed