restic is a modern backup program that’s fast, secure and simple: every backup is a snapshot, data is deduplicated (unchanged data is stored once) and encrypted before it leaves your server, and it supports many storage backends: local disks, SFTP servers, S3-compatible storage, Backblaze B2, and anything rclone supports. It’s an excellent default for VPS backups.
Install
sudo apt install restic # Debian/Ubuntu
sudo dnf install restic # RHEL family (EPEL)
sudo restic self-update # update to the latest release (if installed from a binary)
restic version
Choose a repository
| Backend | Repository string |
|---|---|
| Local disk | /srv/restic-repo |
| SFTP server (e.g. a backup VPS) | sftp:[email protected]:/srv/restic/web1 |
| S3-compatible | s3:https://s3.example-provider.com/my-bucket/web1 |
| Backblaze B2 | b2:my-bucket:web1 |
| REST server (append-only possible) | rest:https://user:[email protected]:8000/web1 |
| Any rclone remote | rclone:remote:path |
Store backups off the server: a backup on the same disk doesn’t survive a lost server. See VPS as a backup server.
Set credentials and initialise
Create an environment file, readable only by root:
sudo tee /root/.restic.env > /dev/null <<'EOF'
export RESTIC_REPOSITORY="s3:https://s3.example-provider.com/my-bucket/web1"
export RESTIC_PASSWORD_FILE="/root/.restic-pass"
export AWS_ACCESS_KEY_ID="…"
export AWS_SECRET_ACCESS_KEY="…"
EOF
sudo chmod 600 /root/.restic.env
openssl rand -base64 32 | sudo tee /root/.restic-pass > /dev/null && sudo chmod 600 /root/.restic-pass
sudo -i
source /root/.restic.env
restic init
Store the repository password somewhere else too (a password manager). Without it, your backups can’t be decrypted. There’s no recovery.
Back up
restic backup /etc /var/www /home /var/backups/db \
--exclude-caches --exclude '/var/www/*/cache' --tag daily
restic snapshots
Back up databases as dumps, not raw data files:
mysqldump --single-transaction --all-databases | restic backup --stdin --stdin-filename mysql.sql
Retention: forget and prune
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
forget removes old snapshots according to the policy. --prune deletes data no longer referenced. Pruning is heavier, so running it weekly is enough on large repositories.
Restore
restic snapshots
restic ls latest /var/www/example.com | head
restic restore latest --target /tmp/restore --include /var/www/example.com
restic restore 1a2b3c4d --target / # full restore of a snapshot (careful)
restic mount /mnt/restic # browse snapshots as files (needs FUSE)
Check integrity
restic check # structure
restic check --read-data-subset=5% # also read and verify 5% of the data
Run checks regularly, and test restores. See backup strategy.
Automate with a script and timer
#!/bin/bash
# /usr/local/bin/restic-backup.sh
set -euo pipefail
source /root/.restic.env
mysqldump --single-transaction --all-databases > /var/backups/db/all.sql
restic backup /etc /var/www /var/backups/db --exclude-caches --tag auto
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
restic check --read-data-subset=1%
Run it nightly with cron or a systemd timer, and alert on failure (for example a healthcheck ping at the end). See crontab and systemd timers.
Protect against ransomware and attackers
If an attacker gets root on your server, they also get the repository credentials, and could delete backups. Mitigations:
- rest-server with
--append-only: clients can add, but not delete. Prune from a separate trusted machine. - Object storage with object lock or versioning (S3 Object Lock, B2 file versions/lifecycle rules).
- A second repository copy (
restic copy) on storage the server can’t write to.
Quick reference
| Task | Command |
|---|---|
| Init | restic init |
| Back up | restic backup <paths> --exclude-caches |
| List | restic snapshots |
| Retention | restic forget --keep-daily 7 … --prune |
| Restore | restic restore latest --target /tmp/r --include <path> |
| Verify | restic check --read-data-subset=5% |
Related: Borg vs restic and rclone.