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 with cp or rsync.

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.

  • Backup
  • Linux
  • rsync