Playbook: Pinbox24 bms-1 Docker Image Backup to Wasabi
Status: ACTIVE
Last updated: 2026-07-01
Origin: #2389 — v32-prod image backup, private registry unreachable
Related: bms-1 v3.x sunset (#745),
pinbox24-s3-wasabi-bms1.md
When to use
A Docker image on bms-1 (94.23.26.113) needs to be preserved to Wasabi because its source
registry is gone or unreachable, and losing the local image (docker system prune -a, disk wipe,
host decommission) would make it unrecoverable. Primary case: the Pinbox24 v3.x/v4.x production
images whose ECR / private-registry.dev.pinbox24.com sources are dead.
The key constraint — bms-1 is unreachable from AI workers
bms-1 root SSH is authorized only from the Windows admin workstation key
(C:\Users\konar\.ssh\id_ed25519, see ssh-key-rotation.md) and the
VPS_ROOT_SSH_KEY GitHub Actions secret. The bms-4 / vps-i1 self-hosted runners and Claude workers
are not in bms-1’s /root/.ssh/authorized_keys — ssh root@94.23.26.113 from them returns
Permission denied (publickey).
Therefore: never try to back up a bms-1 image from a bms-4 worker or the bms4 self-hosted runner. The only automated path is a GitHub-hosted
ubuntu-latestrunner usingVPS_ROOT_SSH_KEY— the same pattern assecrets-sync.yml’ssync-bms-1job.
Automated path (preferred) — GitHub Actions workflow
Workflow: .github/workflows/pinbox24-image-backup.yml
(workflow_dispatch).
What it does
- Loads the bms-1 root key from
VPS_ROOT_SSH_KEYon anubuntu-latestrunner. - Preflight
docker image inspect— aborts if the image is absent. - Streams
docker save <image_ref> | gzipfrom bms-1 straight to the runner (no temp file left on bms-1), then verifies the archive withgzip -t. docker tag <image_id> <backup_tag>on bms-1 (additive named reference).- Uploads to
s3://p24-infra/<dest_key>viaaws s3 cp --endpoint-url https://s3.eu-central-2.wasabisys.com. - Verifies the object size matches the local archive (
s3api head-object). - Cleans up the runner temp files.
- On failure: Discord embed (
DISCORD_WEBHOOK_URL) + GitHub issue (labelbug).
All bms-1 operations are read-only / additive — no container restarts, no deletions.
How to run
Requires the workflow to be present on the default branch (main) for workflow_dispatch to be
available (standard GitHub constraint), then:
gh workflow run pinbox24-image-backup.yml --repo radieu/p24-infra \
-f image_ref='private-registry.dev.pinbox24.com/v32-prod:latest' \
-f image_id='c4167e55cda0' \
-f backup_tag='pinbox24-v32-prod-backup-20260701' \
-f dest_key='pinbox24-images/v32-prod-20260701.tar.gz'
# Watch it:
gh run watch --repo radieu/p24-infra "$(gh run list --repo radieu/p24-infra \
--workflow pinbox24-image-backup.yml --limit 1 --json databaseId --jq '.[0].databaseId')"The default inputs are pre-filled for the #2389 v32-prod case, so a bare
gh workflow run pinbox24-image-backup.yml also works for that image.
Required GitHub secrets (all already present)
| Secret | Purpose |
|---|---|
VPS_ROOT_SSH_KEY | base64 bms-1 root SSH key |
P24_INFRA_WASABI_ACCESS_KEY / P24_INFRA_WASABI_SECRET_KEY | Wasabi p24-infra bucket creds |
DISCORD_WEBHOOK_URL | failure notification |
Manual fallback — from the Windows admin workstation
If the workflow is unavailable (e.g. not yet on main) and the backup is urgent, run from the
workstation that holds the bms-1 root key:
# 1. Save + gzip on bms-1, stream to the workstation (no temp file on bms-1)
ssh root@94.23.26.113 "docker save private-registry.dev.pinbox24.com/v32-prod:latest | gzip" `
> v32-prod-20260701.tar.gz
# 2. Tag locally on bms-1
ssh root@94.23.26.113 "docker tag c4167e55cda0 pinbox24-v32-prod-backup-20260701"
# 3. Upload to Wasabi (aws cli configured with P24_INFRA_WASABI_* creds)
aws s3 cp v32-prod-20260701.tar.gz s3://p24-infra/pinbox24-images/v32-prod-20260701.tar.gz `
--endpoint-url https://s3.eu-central-2.wasabisys.com
# 4. Verify, then delete the local archive
aws s3api head-object --bucket p24-infra --key pinbox24-images/v32-prod-20260701.tar.gz `
--endpoint-url https://s3.eu-central-2.wasabisys.com
Remove-Item v32-prod-20260701.tar.gzRestore
aws s3 cp s3://p24-infra/pinbox24-images/<key>.tar.gz - \
--endpoint-url https://s3.eu-central-2.wasabisys.com | gunzip | docker loadNotes
- Wasabi bucket for infra backups is
p24-infra(regioneu-central-2,s3.eu-central-2.wasabisys.com) — distinct from the Pinbox24 application bucketpinbox24(eu-central-1) documented inpinbox24-s3-wasabi-bms1.md. - The local
docker tagdoes not by itself protect againstdocker system prune -awhen no container references the image — the Wasabi copy is the real backup.