My small home server had “backups” in the sense that I copied things to an external disk when I remembered. I finally set up something automatic with restic.

Why restic: encrypted by default, deduplicated, a single static binary, and it supports local disks, SFTP, and S3-compatible storage with the same commands.

Repository

sudo apt install restic
sudo mkdir -p /etc/restic
sudo sh -c 'openssl rand -base64 32 > /etc/restic/password'
sudo chmod 600 /etc/restic/password

/etc/restic/env:

RESTIC_REPOSITORY=/mnt/backup/restic
RESTIC_PASSWORD_FILE=/etc/restic/password
sudo env $(cat /etc/restic/env) restic init

Copy the password somewhere that isn’t this machine. Without it the repository is just random bytes.

The backup job

/etc/systemd/system/restic-backup.service:

[Unit]
Description=restic backup

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/bin/restic backup --exclude-caches /etc /home /var/lib/docker/volumes
ExecStartPost=/usr/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

/etc/systemd/system/restic-backup.timer:

[Unit]
Description=nightly restic backup

[Timer]
OnCalendar=*-*-* 03:30
RandomizedDelaySec=30m
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer

Persistent=true means a missed run (machine was off) happens at next boot.

Checking it

Once a week I let restic verify a random slice of the actual data, not just the metadata:

restic check --read-data-subset=5%

Test the restore

A backup you’ve never restored is a hope, not a backup. I restored /etc to a temp directory and diffed it:

restic restore latest --target /tmp/restore-test --include /etc
diff -r /etc /tmp/restore-test/etc | head

Next step is a second copy off-site. Since restic speaks S3, that’s mostly a second repository and a restic copy in the same timer.