Hetzner Milestone Runbook
Date: 2026-05-05
Objective
Turn the growing set of Hetzner gates into a safer milestone runner.
The project now has separate helpers for source sync, host readiness, env readiness, Python builds, database migrations, stack startup, health checks, backup checks, and evidence collection. This runbook groups them into reviewable milestones so the server run can stop at the first failing boundary.
What Was Added
scripts/hetzner-runbook.mjsGuarded milestone runner for server-side execution.package.jsonscripts:hetzner:runbook:planhetzner:runbook:commandshetzner:runbook:checkhetzner:runbook:readinesshetzner:runbook:pythonhetzner:runbook:buildhetzner:runbook:databasehetzner:runbook:stackhetzner:runbook:proxy
Safety Rules
- Execution is guarded for native Linux x64/amd64.
- Every run milestone requires
HETZNER_RUNBOOK_CONFIRM=1. - The runner stops at the first failed command.
- Each milestone writes a redacted runbook evidence file to
docs/evidence/. - Each milestone evidence file includes an expected command manifest and command count.
- The status evidence collector still runs at the end of each milestone through
npm run hetzner:evidence:collect. - The runner does not create or edit env files.
- The runner does not perform source sync; source sync remains an explicit local action through
hetzner:sync:*. - The proxy milestone is separate and should only run after internal health is green and DNS/proxy config is real.
Milestones
Print the plan:
npm run hetzner:runbook:plan
Print the raw command list:
npm run hetzner:runbook:commands
Run readiness after source sync, npm install, and real env values:
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:readiness
Run Python services:
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:python
Build remaining services:
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:build
Run database migration/check:
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:database
Start internal stack:
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:stack
Start public proxy only after internal health is green:
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:proxy
Evidence Contract
Each completed milestone writes a file named like:
docs/evidence/<timestamp>-hetzner-runbook-<milestone>.md
Completion evidence must include:
Status: complete
Milestone: <milestone>
Expected command count: <count>
Milestone complete: <milestone>
Platform: linux x64
It must also include every expected command twice:
- once in
## Expected Commands; - once in
## Commandswith the matching numbered command output section.
The final port:completion:* gate now checks this manifest. A thin evidence file that only says Status: complete is not enough.
Local Verification Evidence
node --check scripts/hetzner-runbook.mjspassed.npm run hetzner:runbook:planprints 6 milestones.npm run hetzner:runbook:commandsprints 28 commands.- Future milestone evidence now records
Expected command countplus the expected command manifest. npm run hetzner:runbook:checkfails locally as expected ondarwin arm64.- With
HETZNER_RUNBOOK_ALLOW_NON_HETZNER=1, a run milestone still refuses to execute withoutHETZNER_RUNBOOK_CONFIRM=1. - No local runbook evidence file was generated because no confirmed milestone was executed on this Mac.
Current Boundary
No milestone has been executed on a real Hetzner host yet.
The next real server step is:
HETZNER_SYNC_TARGET="USER@HOST:/opt/LegacyBlinkin-2-Hetzner/" npm run hetzner:sync:dry-run
HETZNER_SYNC_CONFIRM=1 HETZNER_SYNC_TARGET="USER@HOST:/opt/LegacyBlinkin-2-Hetzner/" npm run hetzner:sync:push
Then SSH to the server and start with:
cd /opt/LegacyBlinkin-2-Hetzner/
npm install
npm run hetzner:runbook:plan
HETZNER_RUNBOOK_CONFIRM=1 npm run hetzner:runbook:readiness