Mirror / backup laptop btrfs drive to sometimes connected external USB disk
Maybe using Btrfs send / receive could be made to work, but it is not so simple, because to send a filesystem, a read only snapshot must first be made, and then the name of this snapshot is used on the external disk. I don't think there is a way to receive the root filesystem, at /
This is the best solution. I use snapshots to make fast incremental backups of my servers. You can back up the root subvolume just like any other, but I don't think you can receive at the root. More to the point, you shouldn't do so, because that prevents you from enjoying one of the benefits of snapshotting: incremental backups. Done properly, it will only send the data that has changed and consume only the disk space for the changed data.
This script runs as a cron job and takes a daily snapshot of my root partition, then uses btrfs send
to send an incremental copy to my backup partition. The script as written uses pv
, but if for some reason you don't want to install it, you can simply remove pv
from the middle of the pipes.
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
date=$(date +%Y-%m-%d)
# the path to the partition mount point that we are backing up
source_partition=/
# where backup snapshots will be stored on the local partition
# this is needed for incremental backups
source_snapshot_dir=/snapshots
# where backups will be stored on the backup drive
target_snapshot_dir=/mnt/media/backups/root
if [ ! -d $source_snapshot_dir ]; then
echo 'Creating initial snapshot...'
mkdir --parents $source_snapshot_dir $target_snapshot_dir
# create a read-only snapshot on the local disk
btrfs subvolume snapshot -r $source_partition $source_snapshot_dir/$date
# clone the snapshot as a new subvolume on the backup drive
# you could also pipe this through ssh to back up to a remote machine
btrfs send $source_snapshot_dir/$date | pv | \
btrfs receive $target_snapshot_dir
elif [ ! -d $source_snapshot_dir/$date ]; then
echo 'Creating root volume snapshot...'
# create a read-only snapshot on the local disk
btrfs subvolume snapshot -r $source_partition $source_snapshot_dir/$date
# get the most recent snapshot
previous=$(ls --directory $source_snapshot_dir/* | tail -n 1)
# send (and store) only the changes since the last snapshot
btrfs send -p $previous $source_snapshot_dir/$date | pv | \
btrfs receive $target_snapshot_dir
fi
echo 'Cleaning up...'
# keep the 3 most recent snapshots on the source partition
ls --directory $source_snapshot_dir/* | \
head --lines=-3 | \
xargs --no-run-if-empty --verbose \
btrfs subvolume delete --commit-after
# keep the 28 most recent snapshots on the backup partition
ls --directory $target_snapshot_dir/* | \
head --lines=-28 | \
xargs --no-run-if-empty --verbose \
btrfs subvolume delete --commit-after
(Note: I've adapted the script somewhat to make it into a general solution, and haven't tested it as written. Please feel free to submit revisions if necessary.)