Zero-Downtime Static Deployment
This guide adds a two-stage deployment flow for this Docusaurus site:
- Build and stage a new release without touching current traffic.
- Switch traffic in one atomic symlink update (typically well under one second).
This approach avoids the downtime caused by rebuilding or replacing the same live build/ folder.
What Was Added
- Deploy script:
scripts/deploy-static-release.sh - Rollback script:
scripts/rollback-static-release.sh - Nginx example:
deployment/nginx/aeef-static.conf.example - Manual deploy workflow:
.github/workflows/deploy-static.yml
GitHub Actions Workflow Dispatch
Use the Deploy Static Site workflow (.github/workflows/deploy-static.yml) with:
action=stageto build and upload a release without switching trafficaction=switchto atomically movecurrentto a staged releaseaction=rollbackto switch back toprevious(or a specific release id)
Required Repository Secrets
DEPLOY_HOST— production host/IPDEPLOY_USER— SSH user for deploymentDEPLOY_SSH_KEY— private key for that user
Optional Repository Secrets
DEPLOY_PORT— defaults to22DEPLOY_KNOWN_HOSTS— full known_hosts line for strict host verificationFEEDBACK_ENDPOINTorFEEDBACK_EMAIL— injected at build time
Recommended Dispatch Sequence
- Run workflow with
action=stage. - Confirm staged release exists and smoke check it on host.
- Run workflow with
action=switchand the samerelease_id. - If needed, run
action=rollback.
Directory Layout
/var/www/aeef/
releases/
20260228153045-a1b2c3d/
20260228160750-e4f5g6h/
current -> /var/www/aeef/releases/20260228160750-e4f5g6h
previous -> /var/www/aeef/releases/20260228153045-a1b2c3d
Nginx should serve /var/www/aeef/current.
One-Time Nginx Setup
Use deployment/nginx/aeef-static.conf.example as your server block template and point root to /var/www/aeef/current.
Stage a Release (No Traffic Impact)
From repo root:
scripts/deploy-static-release.sh --install-deps
This builds and copies artifacts into /var/www/aeef/releases/<release-id> but does not switch live traffic.
Atomic Cutover (Live Switch)
When ready:
scripts/deploy-static-release.sh --skip-build --release-id <release-id> --switch --reload-nginx
If you do not pass --release-id, the script stages a new release id and switches that release.
Fast Rollback
Rollback to the previous symlink target:
scripts/rollback-static-release.sh --reload-nginx
Or roll back to a specific release:
scripts/rollback-static-release.sh --to-release <release-id> --reload-nginx
Suggested Deployment Sequence
- Run CI checks (
typecheck, docs checks, build). - Stage release on server (
deploy-static-release.sh --install-deps). - Smoke test staged release path locally on server if needed.
- Switch symlink (
--switch --reload-nginx). - Monitor errors and latency for 5-10 minutes.
- Roll back immediately if needed.
Operational Notes
- Keep build and switch as separate steps.
- Do not let runtime processes serve from a mutable build directory.
- Keep at least one known-good release for instant rollback.