rsync: Deploying Build Artifacts to a Server
A safe artifact deploy is rsync -a with a trailing-slash source, --delete to prune stale files, and protect rules for runtime data.
Deploying a built site to a server is the canonical rsync CI job. The pieces that matter are the trailing slash, --delete safety, and not clobbering server-side state.
What it does
rsync ships only the files that changed since the last deploy, so a 200 MB site that changed two files transfers two files. With -a for fidelity, a trailing-slash source for correct placement, and --delete to remove old assets, you get a clean, fast, idempotent deploy.
Common usage
# Build, then deploy the contents of dist/ as a mirror
rsync -avz --delete --max-delete=200 \
--filter='P uploads/***' \
-e "ssh -i ~/.ssh/deploy_key" \
dist/ deploy@host:/var/www/app/Deploy building blocks
| Flag | Why it is here |
|---|---|
| -a | Preserve modes/times so incrementals work |
| -z | Compress over a non-local link |
| --delete | Remove stale assets from the server |
| --max-delete=N | Abort if a broken build would delete too much |
| --filter='P uploads/***' | Protect runtime data from --delete |
| dist/ | Trailing slash: copy contents, not the dir |
In CI
For near-atomic deploys, rsync into a fresh release directory (releases/<sha>/) and then flip a symlink: ssh host "ln -sfn /var/www/releases/$SHA /var/www/current". That avoids serving a half-synced tree and gives you instant rollback by repointing the symlink.
Common errors in CI
Two land repeatedly: a missing trailing slash nests dist/ inside the target (404s), and a bare --delete after a failed build wipes the site (guard with --max-delete). Run a --dry-run in the pipeline first and fail on unexpected "deleting" lines.