Upgrades
Move the control plane and sandbox hosts to a new version, and what a rollback can and cannot undo.
An upgrade pulls new images for the control plane, runs migrations, then rolls each sandbox host to the same version. Every secret in .env is kept.
Back up first
Take a database dump before every upgrade. It is the only way back from a migration.
# on the control plane, in platinum/infra/compose
docker compose exec -T postgres pg_dump -U platinum -Fc platinum > platinum-$(date +%F).dump
cp .env env-$(date +%F).backupSee Backups.
Upgrade the control plane
Pick the new tag, then pull and restart.
cd platinum/infra/compose
git pull # compose file and Caddyfile changes
./setup.sh --version X.Y.Z # every secret is kept
docker compose pull
docker compose up -d # migrate runs first; the server waits for it
curl https://api.example.com/healthSee Installation for the tags. With PT_API_IMAGE or PT_WEB_IMAGE set, the same tag is pulled from your mirror.
Roll each sandbox host
A host's agents must match the server. Upgrade each host by running a fresh install command on it: mint a new token with the host's region, then run the printed command. The installer only accepts the bundle built with the server it came from.
The installer reboots the host at the end. Move sandboxes off first, one host at a time:
curl -s -X POST https://api.example.com/v1/admin/hosts/<host-id>/drain \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'content-type: application/json' -d '{"dry_run":true}'Drop dry_run to start the drain. After the host is back, check its state in GET /v1/admin/hosts. If it is still draining, return it to service:
curl -s -X POST https://api.example.com/v1/admin/hosts/<host-id>/state \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'content-type: application/json' -d '{"state":"ready"}'Know how migrations run
Each docker compose up -d runs the migrate service before the server starts. It applies two lanes in order.
| Lane | Contains | Applied by |
|---|---|---|
| 1 | Versioned migrations, tracked by hash | bun run db:migrate |
| 2 | Hand-written idempotent SQL | psql, one file at a time |
Both lanes are no-ops when nothing is new. A failed migration stops the rollout before the server starts, and docker compose logs migrate shows where.
Migrations only add to the schema. So a server one release older normally still runs against it.
Roll back
Pin the previous tag and restart.
./setup.sh --version <previous X.Y.Z>
docker compose pull && docker compose up -dThen reinstall each host from the older control plane, as above.