rsnapshot is a small, reliable backup tool built on rsync and hard links. Each backup looks like a full copy of your files (daily.0, daily.1…), but unchanged files are hard-linked, so they take almost no extra space. Restoring is as simple as copying files back. It’s especially good on a backup server that pulls from your other servers.
How it works
- Every run uses rsync to update the newest snapshot (
daily.0). - Older snapshots rotate (
daily.0→daily.1…), and the oldest is deleted. - Files that didn’t change are hard links to the same data, so 7 daily snapshots of a 20 GB site might use only a little more than 20 GB.
- Backups are plain directories: browse them with
ls, restore withcporrsync.
Install
sudo apt install rsnapshot # Debian/Ubuntu
sudo dnf install rsnapshot # RHEL family (EPEL)
Configure /etc/rsnapshot.conf
Important: fields must be separated by tabs, not spaces.
snapshot_root /srv/rsnapshot/
no_create_root 1
retain daily 7
retain weekly 4
retain monthly 6
cmd_ssh /usr/bin/ssh
ssh_args -i /root/.ssh/rsnapshot_key
# local paths
backup /etc/ localhost/
# remote servers (pull over SSH)
backup [email protected]:/etc/ web1/
backup [email protected]:/var/www/ web1/
backup [email protected]:/var/backups/db/ web1/
exclude */cache/*
exclude *.tmp
Test the configuration:
sudo rsnapshot configtest
sudo rsnapshot -t daily # show what would run
Pull backups over SSH
On the backup server, create a key, and authorise it on each source server:
sudo ssh-keygen -t ed25519 -f /root/.ssh/rsnapshot_key -N ""
sudo ssh-copy-id -i /root/.ssh/rsnapshot_key.pub [email protected]
To limit what that key can do, restrict it on the source server with rrsync (read-only rsync):
# /root/.ssh/authorized_keys on web1
command="/usr/bin/rrsync -ro /",restrict ssh-ed25519 AAAA... rsnapshot@backup
The pull model protects history: a compromised web server can’t reach the backup server, to delete old snapshots. See SSH keys and VPS as a backup server.
Databases
rsnapshot copies files. Dump databases on the source server first (cron job before the backup), and include the dump directory:
# on web1
0 1 * * * root mysqldump --single-transaction --all-databases | gzip > /var/backups/db/all.sql.gz
Or use rsnapshot’s backup_exec / backup_script directives to run a dump command as part of the backup. See mysqldump.
Schedule
# /etc/cron.d/rsnapshot
30 2 * * * root /usr/bin/rsnapshot daily
0 4 * * 1 root /usr/bin/rsnapshot weekly
30 4 1 * * root /usr/bin/rsnapshot monthly
Run the larger intervals before the daily run would overlap, and make sure each run finishes before the next starts. See crontab.
Restore
ls /srv/rsnapshot/daily.2/web1/var/www/example.com/
rsync -a /srv/rsnapshot/daily.2/web1/var/www/example.com/ [email protected]:/var/www/example.com/
Limitations
- No encryption: files are stored as-is. Encrypt the backup server’s disk, or use restic/Borg for untrusted storage. See restic backup.
- No deduplication across files (only unchanged files are shared between snapshots). A renamed or slightly changed large file is stored again.
- Needs a filesystem that supports hard links (ext4, XFS, Btrfs: not object storage).
Monitoring
rsnapshot writes to /var/log/rsnapshot.log (set logfile in the config). Check it after the first runs, and add an alert: for example, a cron wrapper that pings a healthcheck URL only when rsnapshot exits successfully. Also watch the backup disk’s free space and inode usage (df -h, df -i): hard-linked snapshots use many inodes on systems with lots of small files.
Quick reference
| Task | Command / setting |
|---|---|
| Config | /etc/rsnapshot.conf (tabs!) |
| Check | rsnapshot configtest |
| Dry run | rsnapshot -t daily |
| Retention | retain daily 7 etc. |
| Pull over SSH | backup root@host:/path/ host/ |
| Restrict key | rrsync -ro / |
Related: rsync examples and Borg vs restic.