Deploy Pipeline
Deploy Pipeline
Migration in progress.
api.legendary-arena.comand its PostgreSQL are moving off Render onto a self-hosted DigitalOcean Ubuntu droplet fronted by Cloudflare, perdocs/PLAN.md. Until decommission, Render stays warm as the rollback target.
Summary
The deploy pipeline is a GitHub Actions workflow that ships the application to the droplet over SSH on every push to main. It pulls, installs, builds, migrates, and reloads the la-server service — replacing Render’s push-to-main auto-deploy.
Mechanics
The owning artifact is .github/workflows/deploy.yml
. Step by step:
- Trigger — fires on
pushtobranches: [main]or manually viaworkflow_dispatch, and the job is guarded byif: vars.DEPLOY_ENABLED == 'true' && github.ref == 'refs/heads/main'. Until the droplet exists, theDEPLOY_ENABLEDrepository variable is unset, so the job is skipped (neutral) rather than failing on the missing host; setDEPLOY_ENABLED=trueonce the deploy secrets point at a real droplet (Phase 1+). - Checkout —
actions/checkout@v4checks out the repo on theubuntu-latestrunner. - SSH in —
appleboy/ssh-action@v1.2.0connects to the droplet using theDEPLOY_HOST,DEPLOY_USER, andDEPLOY_SSH_KEYGitHub secrets. - On-host script — runs under
set -euo pipefail:
cd /opt/legendary-arena
git pull --ff-only origin main
pnpm install --frozen-lockfile
pnpm -r build
node scripts/migrate.mjs
sudo systemctl reload la-server
This replaces Render’s push-to-main auto-deploy, per docs/PLAN.md
. Note the pipeline runs migrations inline via node scripts/migrate.mjs — unlike the app-deploy path that gates migrations behind a RUN_MIGRATIONS flag, here they run unconditionally on every deploy.
Interactions
- Deploy Server — the manual, first-run equivalent of this pipeline; both build the app and reload the service.
- Node Runtime
— provides the pnpm and Node on the box that the on-host
pnpm install/pnpm -r buildsteps depend on. - Render-to-DigitalOcean Migration — this pipeline is the Phase 4 replacement for Render’s auto-deploy.
.github/workflows/deploy.yml— the owning workflow.
Edge Cases
- Until
DEPLOY_ENABLEDis set totrue, the job is skipped by design — a pre-Phase-1 guard so an unsetDEPLOY_HOSTdoes not red-X every merge tomain. Enabling it before the droplet and its three secrets exist just restores themissing server hostfailure. - The three GitHub secrets
DEPLOY_HOST,DEPLOY_USER, andDEPLOY_SSH_KEYmust be set or the SSH step fails immediately. git pull --ff-onlyfails if the on-host tree has diverged or carries local commits, halting the deploy before any build.- A failed migration leaves a half-deployed state:
set -euo pipefailmeans thesystemctl reloadonly happens if every prior step succeeds. - This is the load-bearing “develop from anywhere” loop; rollback of a bad deploy means repointing to Render or reverting the commit and re-pushing.
Execute
The pipeline runs automatically on any push to main. To trigger it manually (the workflow_dispatch path):
gh workflow run "Deploy API Host"
Verify
Check the run status from the workflow name:
gh run list --workflow="Deploy API Host"
Then confirm the service on the host:
systemctl status la-server
curl -s localhost:3000/health
A healthy service returns from /health on port 3000.
References
.github/workflows/deploy.yml— owning artifact, the deploy workflow.docs/PLAN.md— migration plan; the pipeline replaces Render’s push-to-main auto-deploy.- Deploy Server — manual/first-run deploy equivalent.
- Node Runtime — pnpm/Node runtime the on-host steps use.
- Render-to-DigitalOcean Migration — Phase 4 context for the auto-deploy replacement.