Context
Deploying by copying changed files over a live tree risks a window where visitors see a partial release: some files are new, others old, and associated resources disagree. A malformed single file can also corrupt an otherwise fine live site. Any release path that edits the served directory in place makes the “previous release” difficult to name and restore.
Decision
Publish by staging a complete new tree beside the live tree, then renaming the single directory Caddy serves to point at it. The old tree remains on disk under its prior name.
rsync -a public/ /srv/www/example-site.new/
mv /srv/www/example-site.new /srv/www/example-site
Because the serve root is one directory name, the swap is atomic from the client’s perspective: every request resolves to either the old complete tree or the new complete tree, never a mix.
Consequences
- No partial states: a visitor always sees one coherent release.
- Cheap rollback: the old tree still exists; recovery is a reverse rename.
- Verifiable before swap: the staged tree can be checked and hashed before it becomes the served one.
- Storage trade-off: the server holds the current tree plus a staged tree; the extra disk is the price of atomicity.
Why this beats in-place sync
In-place sync promises to adjust a live tree, but it cannot answer the question “which bytes are being served right now” atomically, and it complicates rollback to “yesterday”. Complete-directory exchange answers the release question with one durable fact — the served directory name — and makes both forward and backward moves a single rename.
Sources
- Martin Fowler: BlueGreenDeployment, complete-tree versus blue-green/staged exchange models, checked 2026-08-20.
- POSIX
rename(), atomic rename semantics underpinning the swap, checked 2026-08-20.