btrfs Snapshots and Backups
One of the btrfs killer-features is snapshots and its CoW.
A Snapshot is a subvolume which has a parent subvolume.
It stores only the changes by creating a copy on writes.
Snapshots can be read-only.
Like any other subvolumes snapshots can be mounted.
A Simple test run
# Create a snapshot echo before snap > /home/$USER/test btrfs subvolume snapshot /home /mnt/snaps/home-old echo after snap > /home/$USER/test cat /home/$USER/test # after snap cat /mnt/snaps/home-old/$USER/test # before snap
as expected :)
btrfs subvolume delete /mnt/snaps/home-old
Snapshots for Backups
Snapshot are excellent for backups.
- Since they are ordinary mounts we need no fancy tool for recovering.
Just jump into the directory and pick the files you need.
- No worry about permissions, ownerships, ACLs …
- No need to iterate over ~1e12 small files and compare mtime.
- No changes during the backup process
You’ll ask yourself: Backup on the same disk?
Of course not.
btrfs is capable to create a readable binary stream from a subvolume using
btrfs send. It’s counterpart
btrfs receive writes updates to a given
subvolume. Additionally, it allows to transfer the difference between two snapshots:
btrfs send -p snapYesterday snapToday.
Note: btrfs-send needs read-only snapshots!
backup.home is a machine with btrfs and ssh. We can now transfer
the subvolume over the network.
# Create a read-only snapshot btrfs subvolume snapshot -r /home /mnt/backup # Initially transfer the whole subvolume btrfs send /mnt/backup | ssh firstname.lastname@example.org btrfs receive /mnt/homeFromPC
# Transfer the changes since `backup` btrfs subvolume snapshot -r /home /mnt/backup-new btrfs send -p /mnt/backup /mnt/backup-new | ssh email@example.com btrfs receive /mnt/homeFromPC
Neat, isn’t it?
A script could help to create daily backup snapshots, transfer them and delete the outdated. Fortunately there are nice tools around: Available Backup Tools
I picked btrbk cause its fits perfect for my case.
Backups to a none-btrfs target
Obviously, my target is not btrfs powered.
The solution is sshfs + image files.
# Mount the remote target sshfs -o uid=0 -o gid=0 -o reconnect remote:backups /mnt/remote # Create a image file (100GB) dd if=/dev/zero of=/mnt/remote/btrfs-1.img bs=1 seek=100G count=1 # Make it btrfs mkfs.btrfs /mnt/remote/btrfs-1.img # Mount it mount /mnt/remote/btrfs-1.img /mnt/backup
You could now use
/mnt/backup as btrfs backup target.
Out of space
Time is passing, things are growing.
No Problem for btrfs.
Just add another device
# Create another image file: btrfs-2.img dd if=/dev/zero of=/mnt/remote/btrfs-2.img bs=1 seek=100G count=1 # Add it btrfs device add /mnt/remote/btrfs-2.img /mnt/backup # Check it btrfs filesystem show /mnt/backup
Untrusted target? Encryption!
Thanks to the image files it is possible to add an encryption layer.
# Create a image file (100GB) dd if=/dev/zero of=/mnt/remote/btrfs-1.img bs=1 seek=100G count=1 # Create a password key file echo "my-32-char-super-secret-password" > /root/luksKey # Encrypt the image cryptsetup luksFormat --key-file=/root/luksKey /mnt/remote/btrfs-1.img # Decrypt and create a mapper device cryptsetup luksOpen --key-file=/root/luksKey /mnt/remote/btrfs-1.img backup_btrfs-1
You can now use the
/dev/mapper/backup_btrfs-1 device to setup
your encrypted remote btrfs backup target.
That’s it :)
PS: I use this setup currently on one of my Hetzner root servers in conjunction with a StorageBox.