An untested backup is a guess. Restic backup gives you encrypted, deduplicated, verifiable backups, and this walkthrough sets one up end to end: initialise an encrypted repository, run a backup, schedule it with a systemd timer, apply a retention policy, and, most importantly, perform a real restore and integrity check. So, a backup you have never restored does not count.
Prerequisites
- A Linux host with data worth backing up.
- A backend for the repository. This uses an S3-compatible bucket; restic also supports SFTP, local disk, and more.
Step 1: install restic and store the credentials
sudo apt update && sudo apt install -y resticKeep the repository details and encryption password out of your command history in an env file, readable only by root:
sudo mkdir -p /etc/restic
sudo tee /etc/restic/password > /dev/null <<'EOF'
choose-a-long-random-passphrase-and-store-it-in-your-password-manager
EOF
sudo tee /etc/restic/env > /dev/null <<'EOF'
RESTIC_REPOSITORY=s3:https://s3.amazonaws.com/your-backup-bucket
RESTIC_PASSWORD_FILE=/etc/restic/password
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
EOF
sudo chmod 600 /etc/restic/password /etc/restic/envWrite the password somewhere safe now. If you lose it, the data is gone: there is no recovery path, and that is the point of the encryption.
Step 2: initialise the repository and run the first restic backup
set -a; source /etc/restic/env; set +a
restic init
restic backup /etc /var/www /home --tag daily
restic snapshotsrestic snapshots lists the backup you just made with its ID and timestamp.
Step 3: schedule it with a systemd timer
Create the service, which backs up and then prunes old snapshots:
sudo tee /etc/systemd/system/restic-backup.service > /dev/null <<'EOF'
[Unit]
Description=restic backup
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/bin/restic backup /etc /var/www /home --tag daily
ExecStartPost=/usr/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
EOFAnd the timer:
sudo tee /etc/systemd/system/restic-backup.timer > /dev/null <<'EOF'
[Unit]
Description=Run restic backup daily
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl list-timers restic-backup.timer --no-pagerPersistent=true means a missed run (server was off at 02:00) happens at next boot.
Step 4: test a real restore and verify integrity
This is the step people skip. Restore a file to a scratch directory and confirm the contents:
set -a; source /etc/restic/env; set +a
restic restore latest --target /tmp/restore-test --include /etc/hostname
cat /tmp/restore-test/etc/hostnameThen verify the repository is not silently corrupt. check validates structure; the read-data sample actually re-reads and hashes a slice of the data:
restic check
restic check --read-data-subset=5%Therefore, put a full restore drill on the calendar, not just a file restore. The first time you do a real restore should not be during an outage.
What goes wrong
Lost encryption password. There is no recovery. Store it separately from the server, in a password manager.
Repository is locked. A previous run was interrupted. Clear stale locks with restic unlock (only when no backup is actually running).
Repository keeps growing. You are running backup but not forget --prune. The ExecStartPost line above handles it; confirm it is running.
Backups of a live database are inconsistent. Copying database files while the engine is writing gives you a corrupt restore. Back up a dump (pg_dump, mysqldump) or a filesystem snapshot instead of the live data directory.