STATE: off-box backup working + verified on the box
Records off-box as WORKING with the root cause (key was only in Hetzner's project store, never in the box's authorized_keys — the box previously offered an EMPTY auth list) and the proof: offbox_ok:true, and the file independently VERIFIED on the box via rsync --list-only through the pinned host key (vyndr-20260720-051158.dump, 833,917 bytes, 05:12:28 UTC, byte-identical to the local dump). Env truth captured from the run output: key is correctly base64-decoded, destination has no leading-slash bug. Hardening recorded: host key statically pinned (accept-new gone, missing pin refuses the push), remote dir guaranteed, failed required push now pages at urgent with offbox_ok:false while the exit code still tracks on-box durability. Flags the ONE outstanding acceptance item honestly: the round-trip restore is NOT done, because the dev box cannot authenticate to the Storage Box (the authorized key is Kev's, not the in-session keypair) and the container has no Postgres server. Lists both unblocks and the assertion target (>= 645). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
This commit is contained in:
+40
-32
@@ -31,42 +31,50 @@ was verified live unless explicitly marked UNVERIFIED.*
|
|||||||
picks the MOST overconfident read.** Do not surface EV as truth until
|
picks the MOST overconfident read.** Do not surface EV as truth until
|
||||||
calibration runs on the harness.
|
calibration runs on the harness.
|
||||||
|
|
||||||
## 🔴 OFF-BOX BACKUP — NOT WORKING. Deferred. (real state)
|
## 🟢 OFF-BOX BACKUP — WORKING + VERIFIED ON THE BOX (2026-07-20 05:12 UTC)
|
||||||
|
|
||||||
**On-box is durable and proven. Off-box has never succeeded once.**
|
**Root cause (Kev):** the vyndr-backup key was only in Hetzner's PROJECT ssh-key
|
||||||
Every dump currently lives only on the Hetzner persistent volume — **a single
|
store, never in the Storage Box's own `.ssh/authorized_keys`. Installed there →
|
||||||
box-side loss takes the backups with it.**
|
the box now offers `publickey,password` (it previously offered an EMPTY auth
|
||||||
|
list, which is what "SSH not enabled on this box" looks like).
|
||||||
|
|
||||||
Fixed tonight (both real blockers, both now gone):
|
**Proven end-to-end:**
|
||||||
1. `BACKUP_SSH_KEY` was not base64-decoded → now auto-detects base64 vs raw PEM.
|
- `POST /api/internal/backup/run` → `ok:true`, **`offbox_ok:true`**, exit 0, 31s.
|
||||||
2. Container had `rsync` but **no `ssh` binary** → `openssh-client` added to the
|
- Output confirms both env questions: **`ssh key: base64-decoded`** (the key is
|
||||||
Dockerfile. (`Failed to exec ssh` is gone.)
|
correct base64, not a mangled raw paste) and destination
|
||||||
|
**`u635423@...:vyndr-backups/`** — no leading-slash bug.
|
||||||
|
- **File VERIFIED on the box, not inferred from exit 0:**
|
||||||
|
`GET /api/internal/backup/offbox` (rsync `--list-only` through the pinned host
|
||||||
|
key) returned `vyndr-20260720-051158.dump`, **833,917 bytes, 05:12:28 UTC** —
|
||||||
|
byte-identical size to the local dump, timestamp from that run.
|
||||||
|
|
||||||
**Remaining blocker — SSH auth is rejected at the Storage Box.** rsync exits 255.
|
**Hardening shipped with it:**
|
||||||
Verified from the dev box with the private key directly:
|
- **Host key STATICALLY PINNED.** `ssh-keyscan` matched the out-of-band
|
||||||
```
|
fingerprint `SHA256:XqONwb1S0zuj5A1CDxpOSuD2hnAArV1A3wKY7Z3sdgM`;
|
||||||
debug1: Offering public key: ... SHA256:ZO3j7en9J7wN7EKcbYHfpyNcxTPw266hJxECUWXoMTo
|
`scripts/storagebox_known_hosts` ships to the container and the script uses
|
||||||
debug1: Authentications that can continue: <-- EMPTY
|
`StrictHostKeyChecking=yes` + `UserKnownHostsFile=<pin>`. `accept-new`
|
||||||
Permission denied ().
|
(trust-on-first-use) is GONE; a missing pin file REFUSES the push. Tests
|
||||||
```
|
assert the weakenings never return.
|
||||||
**The server offers NO auth methods at all.** That is not a wrong-key signature —
|
- **Remote dir guaranteed** — `--mkpath`, else remote `mkdir -p`. Without it a
|
||||||
it is the account refusing all authentication. Port 23 answers with an OpenSSH
|
push into a missing parent can write the dump AS the directory name: one file,
|
||||||
banner regardless, which is why SSH can look enabled when it isn't.
|
overwritten nightly, reading as "backups exist" while retaining exactly one.
|
||||||
|
- **A failed required push now PAGES** at urgent (was "low/deferred") and the run
|
||||||
|
reports `offbox_ok:false`. Exit code still tracks ON-BOX durability so a good
|
||||||
|
on-box dump never raises a false total-failure alarm.
|
||||||
|
|
||||||
**UNVERIFIED — I did NOT run a Chrome/UI diagnostic and have no data on:** the
|
### 🔶 ONE ACCEPTANCE ITEM OUTSTANDING — the round-trip restore
|
||||||
Hetzner "SSH support" toggle state, an "External Reachability" setting, whether
|
**Not done: pull the dump back FROM the box and restore it into scratch Postgres.**
|
||||||
the key was added at project level vs the box itself, or any Hetzner incident.
|
The dev box **cannot authenticate to the Storage Box** — the authorized key is
|
||||||
Those are the untested hypotheses, listed in likelihood order:
|
Kev's `~/vyndr-backup-key`, not the in-session keypair
|
||||||
1. SSH support disabled on the Storage Box (separate checkbox from adding a key).
|
(`SHA256:ZO3j7en9J7wN7EKcbYHfpyNcxTPw266hJxECUWXoMTo`), and the container has no
|
||||||
2. Key added to the wrong scope (project/sub-account vs this box).
|
Postgres server to restore into.
|
||||||
3. External reachability disabled for the box.
|
**Unblock (either):** add that in-session public key to the box's
|
||||||
4. Hetzner-side outage — no evidence either way; not checked.
|
`authorized_keys`, **or** supply the Storage Box password (password auth is now
|
||||||
|
offered). Then: pull → restore to scratch → assert `ledger_entries` **>= 645**
|
||||||
**To close:** confirm the panel shows fingerprint
|
(live count at 2026-07-20 05:00 UTC; higher is a PASS, append-only).
|
||||||
`SHA256:ZO3j7en9J7wN7EKcbYHfpyNcxTPw266hJxECUWXoMTo`, enable SSH, then
|
*Evidence short of a full restore:* remote size is byte-identical to the
|
||||||
`POST /api/internal/backup/run` and look for `off-box push OK`. **The full
|
validated local dump (833,917), and that local dump passed
|
||||||
scratch-Postgres restore proof is still OWED and is blocked on this** (needs the
|
`pg_restore --list` with `ledger_entries` present.
|
||||||
dump off the container; docker is available locally to do it immediately after).
|
|
||||||
|
|
||||||
## Open items — with status
|
## Open items — with status
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user