08 from Backups Verified by Restore — Twelve Days of OK Over an Empty Archive
The restore proof: a backup counts once a clean machine brings it back
By Vladimir Mikhalev Docker Captain · CNCF Ambassador · IBM Champion
A backup that has only ever been listed has not been shown to restore. It is an archive with a hopeful name.
The proof has three parts with three owners: the archive opens, the shipped script brings the data back, and a machine with nothing on it brings the service back. The clean-machine drill is the third part, and the only one that produces a recovery time an auditor can be given.
- 1
Read the archive back before it gets its name
Nothing carries the name a restore would pick until it has been opened: an integrity test for a compressed dump, a full listing for an archive, and for a database a load into a throwaway container compared with the live schema table for table. A floor of “more than ten tables” passes a dump that restored a fifth of the schema.
- 2
Run the shipped restore script, not a copy of its commands
Write a marker, wait for a backup whose cycle started after it, destroy the live state, run the file an operator would run, and require the marker back through the application, not through the database.
- 3
Prove the prune
Plant an archive older than the retention window beside the real ones. After the next cycle it is gone and the recent ones stay. A prune that is only intended is not a prune.
- 4
Restore on a machine that never ran the stack, weekly
The previous release's backup into the current release, on a runner that has never seen it. That run finds what the dump does not carry: server accounts, generated secrets, files written at install time.
- 5
Publish the number with its run, and refuse a report without it
One row per drill: from and to release, pass or fail, seconds, the backup interval as the bound on loss, and the run link. A failed drill is a row with no time. A file carrying fewer than half the drills of the last published one is refused, not shown.
- 6
Give the number an owner
SRE, with the figure on the page they would be asked for.
Measured on a clean machine, week of 8 November 2026
| Measure | Result | Where it is |
|---|---|---|
| Templates restored | 46 of 47 | The weekly drill, 8 November 2026 |
| Fastest, SiYuan | 18 seconds | Run 42475961949 |
| Slowest, Jira | 6 minutes 10 seconds | Run 42475927543 |
| Median, all 46 | 72 seconds | The evidence page |
| Failed, Dify | No time; shown as failed | Run 42475992937 |
| Bound on loss | 24 hours, the backup interval, for the 46 of 47 templates that publish one | Each template's own setting |
What shows it works
Three decisions, the drill, and runs anyone can open.
- Decision 4, 2 September 2026: a backup is proven by a restore, in CI, on every push.
- Decision 12, 23 September 2026: CI runs the restore script the operator would run, not a copy of its commands.
- Decision 14, 23 September 2026: recovery time is measured weekly on a machine that has never run the stack, from the previous release into the current one.
- The week of 8 November 2026 on the evidence page, and its runs: SiYuan, 18 seconds, Jira, 6 minutes 10 seconds, Dify, failed.
- The AnythingLLM template's run that restores and then writes, 19 October 2026.
- restore-drill v1.1.0: the single-host version, a dump loaded into a throwaway container on a timer and compared with the live tables.
- The ledger, backups: every backup finding, with the rule it produced.
A backup is the one a clean machine brought back.
The long versions are the posts Backups Verified by Restore and Restore Drills on a Clean Machine. ISMS.online on ISO 27001 8.13; AICPA, 2017 Trust Services Criteria (2022 points of focus), criterion A1.3.