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_keysssh 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-latest runner using VPS_ROOT_SSH_KEY — the same pattern as secrets-sync.yml’s sync-bms-1 job.

Automated path (preferred) — GitHub Actions workflow

Workflow: .github/workflows/pinbox24-image-backup.yml (workflow_dispatch).

What it does

  1. Loads the bms-1 root key from VPS_ROOT_SSH_KEY on an ubuntu-latest runner.
  2. Preflight docker image inspect — aborts if the image is absent.
  3. Streams docker save <image_ref> | gzip from bms-1 straight to the runner (no temp file left on bms-1), then verifies the archive with gzip -t.
  4. docker tag <image_id> <backup_tag> on bms-1 (additive named reference).
  5. Uploads to s3://p24-infra/<dest_key> via aws s3 cp --endpoint-url https://s3.eu-central-2.wasabisys.com.
  6. Verifies the object size matches the local archive (s3api head-object).
  7. Cleans up the runner temp files.
  8. On failure: Discord embed (DISCORD_WEBHOOK_URL) + GitHub issue (label bug).

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)

SecretPurpose
VPS_ROOT_SSH_KEYbase64 bms-1 root SSH key
P24_INFRA_WASABI_ACCESS_KEY / P24_INFRA_WASABI_SECRET_KEYWasabi p24-infra bucket creds
DISCORD_WEBHOOK_URLfailure 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.gz

Restore

aws s3 cp s3://p24-infra/pinbox24-images/<key>.tar.gz - \
  --endpoint-url https://s3.eu-central-2.wasabisys.com | gunzip | docker load

Notes

  • Wasabi bucket for infra backups is p24-infra (region eu-central-2, s3.eu-central-2.wasabisys.com) — distinct from the Pinbox24 application bucket pinbox24 (eu-central-1) documented in pinbox24-s3-wasabi-bms1.md.
  • The local docker tag does not by itself protect against docker system prune -a when no container references the image — the Wasabi copy is the real backup.