The idea
A scheduled service that doesn't just check whether a backup job ran and produced a file of nonzero size — it actually restores a random sample of that backup into an isolated scratch environment, verifies checksums, runs a database SELECT count(*) or opens a few files, and reports pass/fail. It plugs into whatever you already use to produce backups (pg_dump, restic, borg, tar, rsync snapshots) and treats "restore succeeded and data is readable" as the only signal that matters.
Why build this
Everyone has a backup script. Almost nobody has verified their backup actually restores until the day they need it, and by then it's too late to find out cron silently stopped writing three weeks ago, or the encryption key rotated and nothing decrypts, or the dump is truncated because disk filled up mid-job. Backup existence monitoring (file appeared, size > 0) catches maybe half of real failure modes. Restore verification catches the other half, and it's the half that actually matters. Small self-hosted operators — the exact audience running Postgres, n8n, and Ollama on a single VPS — are the least likely to have this and the most exposed if it fails.
Stack sketch
- Core: a small Go or Python CLI (
bvfy) that runs as a cron job or one-shot container - Restore targets: spin up ephemeral containers via the Docker socket (postgres, mysql, sqlite) to restore into, torn down after each run
- Backup source adapters: local path, S3-compatible bucket (MinIO, Backblaze, Wasabi), restic/borg repo
- Verification checks: checksum match against manifest, row-count sanity check per configured table, file-open smoke test for non-DB archives (tar/zip integrity + sample extraction)
- Reporting: writes a JSON result + pushes to a webhook (ntfy, Slack, or straight into an existing Uptime Kuma push monitor)
- Config: single YAML file describing backup sources, restore method, and pass/fail thresholds
Scope for v1
- In: Postgres dump restore + row-count check, tarball integrity + sample file extraction, local disk and S3-compatible sources, webhook notification on failure, a
bvfy runCLI you cron yourself - Out: MySQL/SQLite adapters, a web dashboard, historical trend charts, automatic remediation, multi-tenant/team accounts
- Out for v1: verifying encrypted backups beyond "decrypts successfully" — no content diffing against production
Where it could go
Next step is a lightweight dashboard showing a calendar heatmap of verification runs per backup source, so you can see at a glance which systems have gone unverified longest — that's the natural companion to something like Uptime Kuma, which watches services but not backup integrity. After that, point-in-time restore drills: instead of just the latest backup, periodically restore a backup from a week or a month ago to catch slow-creeping corruption or a retention policy that's silently deleting things too early.
Watch out for
Restoring production-scale databases into ephemeral containers costs real CPU, memory, and time — sampling strategy (restore only recent partitions, or a random table subset) matters a lot once source data grows past a few gigabytes, or verification runs become too slow or expensive to run daily.