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.)