How to test that your restic backups actually restore
A backup job that finished tells you data was written. It doesn't tell you that you can get it back. Here is how to prove it — by hand first, then automatically.
Why "the backup ran" is not enough
When restic backup exits with code 0, the files it read were stored in the repository. That is all. Between that moment and the day you need a restore, a lot can go wrong:
- The repository gets damaged later — a failing disk, a bad NAS, an interrupted prune, a bucket lifecycle rule that deleted files.
- The important data was never in it — a path was renamed, an exclude pattern was too wide, or the database dump the backup picked up was empty.
- Some files were skipped — restic exits with code
3when it could not read some source files. Many scripts treat that as success. - You can't open it — the password file lives only on the server that just died.
The only test that covers the whole chain is the one you'll do on a bad day: take data out of the repository and check that it's right.
Quick manual test: restore one file
Set the repository and password the same way your backup job does, then look at the newest snapshot:
export RESTIC_REPOSITORY=/srv/restic-repo
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic snapshots --latest 1
Restore a single file into a scratch directory and compare it with the original:
restic restore latest --target /tmp/restore-test --include /etc/hostname
cmp /etc/hostname /tmp/restore-test/etc/hostname && echo "restore OK"
You can skip the scratch directory: restic dump writes a file from a snapshot to stdout.
restic dump latest /etc/hostname | cmp - /etc/hostname && echo "restore OK"
This only works for a file that hasn't changed since the backup. A file that changes all the time will "fail" even when the backup is fine — which is why the next step uses a file you control.
Make it reliable: a canary file
A canary is a small file you write right before each backup, with content you can predict. After the backup, you read it back from the new snapshot. If it matches, you know three things at once: the backup ran, it contains this run's data, and the repository can give data back.
# before the backup: write the canary
date -u +%Y-%m-%dT%H:%M:%SZ > /var/lib/restic-canary
# the backup itself — make sure the canary's path is included
restic backup /etc /home /var/lib/restic-canary
# after the backup: read it back from the newest snapshot
restic dump latest /var/lib/restic-canary | cmp - /var/lib/restic-canary
If several machines share one repository, add --host "$(hostname)" to restic dump so latest means this machine's newest snapshot.
Automate it
Put the whole sequence in one script and let it shout when something is off. This version mails root; swap the alert function for whatever you use (a chat webhook, a monitoring push).
#!/bin/bash
set -uo pipefail
export RESTIC_REPOSITORY=/srv/restic-repo
export RESTIC_PASSWORD_FILE=/root/.restic-pass
CANARY=/var/lib/restic-canary
alert() { echo "$1" | mail -s "restic on $(hostname): $1" root; }
date -u +%Y-%m-%dT%H:%M:%SZ > "$CANARY"
restic backup /etc /home "$CANARY"
rc=$?
if [ $rc -eq 3 ]; then
alert "backup finished, but some files could not be read"
elif [ $rc -ne 0 ]; then
alert "backup failed (exit $rc)"; exit 1
fi
if ! restic dump --host "$(hostname)" latest "$CANARY" | cmp -s - "$CANARY"; then
alert "restore test FAILED: the canary did not come back"
exit 1
fi
Run it from a systemd timer or cron at the time your backup already runs. Keep a copy of the repository password somewhere other than this server — a password manager or a sealed envelope. A restore test on the server proves nothing about the day the server is gone.
What this test does not prove
Restoring one file reads only the few pack files that hold it. It proves the chain works today, not that every byte in the repository is intact. Old snapshots and big files you never restore could still be damaged. For that you need restic check --read-data, which is expensive on large or cloud repositories — see restic check vs --read-data vs --read-data-subset for how to spread it out.
And a test that nobody looks at is not a test. Make sure a failure reaches a person — more on that in How to monitor restic backups.
Doing this on every server, every day?
Vaultwitness runs these checks for you: a restore test of the newest snapshot, repository checks, a full data re-read spread over many nights and alerts when a backup is late — on all your servers, in one self-hosted dashboard. Free for 2 servers.
Download free