Does anyone have a good, simple btrfs snapshot backup solution?

I’m looking for a simple setup which will take daily snapshots of /home and then send those snapshots to a second drive, keeping exactly a month’s worth. I already have an online backup solution; this would primarily be for convenience in the event of drive failure or quickly grabbing a file I deleted by mistake.

Most of the things I’ve looked at have what seems like extra complexity for my use case.

I started with btrbk, because that’s packaged in Fedora, but it has instructions which start like with In this example, we assume you have a laptop with a disk having a btrfs root subvolume (subvolid=5) mounted on /mnt/btr_pool…. and that doesn’t seem like the setup we have in Fedora Workstation by default. And it seems really geared for backup to remote systems, which is great and all but not what I need.

Maybe this can all be done with a simple shell script run nightly from cron? I looked at the btrfs subvolume snapshot, btrfs send and btrfs receive commands, which seem to be the basic building blocks for what I want, but they’re really short on examples. Is there a place I can find good ones?

2 Likes

The program timeshift looks a lot like what I want, except it is focused entirely on system partitions and doesn’t do user data, which is the opposite of what I want.

2 Likes

A variation on the above article that I use is putting the snapshots in the “top-level” of the file system. I do this just for organizational reasons, it keeps the snapshots out of the /home search path where otherwise they affect find, locate, and du commands.

For example (sudo implied):

mount /dev/sdXY /mnt/internal
cd /mnt/internal
ls -l

By default you’ll see what looks like two directories, root and home but these are actually subvolumes.

btrfs sub snap -r home home.20210122

The convention I’m using is anything with a date stamp is a read-only snapshot. You can certainly make this a one-shot systemd service and associate it with a timer unit for once per day or per hour.

btrfs send -p home.20210121 home.20210122 | btrfs receive /mnt/backup

Just like in the article, but with my own naming convention. This assumes the home.20210121 snapshot is already on the destination. The initial send/receive is described in the article.

To restore individual files, you can just copy them out of the backup using the file manager. There’s nothing special about the files or snapshots in this regard.

6 Likes

btrbk works fine for me. What I did to make it work:

  • remount my home partition to /mnt/hdd-home via fstab
  • set a mount point for my backup USB HDD to /mnt/hdd-home-backup via fstab
  • adjust btrbk’s config accordingly

Of course there is no ‘generic’ solution for any scenario but with a bit of work your recurring backup comes down to

  • plug in your backup drive
  • mount and decrypt
  • run btrbk run
  • unmount and plug out
  • done
1 Like

You could use this template (it is missing your time limit setting) as a baseline.

#!/usr/bin/env bash
# Needs to be run with sudo
if [ "$EUID" -ne 0 ]; then
    echo "This script needs to be run with sudo or as a root user"
    exit 1
fi
LOCALSNAPSHOTSDIR="/.snapshots"
EXTERNALSNAPSHOTSDIR="/run/media/btrfs_formatted_drive"

LATEST_HOME=(`ls -d $LOCALSNAPSHOTSDIR/home-* | sort | tail -c 9`)
LATEST_HOME_EXTERNAL=(`ls -d $EXTERNALSNAPSHOTSDIR/home-* | sort | tail -c 9`)
TODAY=`date +%Y%m%d`

# make local snapshot
if test -d "$LOCALSNAPSHOTSDIR"; then
    echo "Using directory $LOCALSNAPSHOTSDIR for local snapshots."
    if [[ $LATEST_HOME -ne $TODAY ]]; then
        echo "Today is $TODAY and latest home backup was $LATEST_HOME doing new snapshot"
        btrfs subvolume snapshot -r /home $LOCALSNAPSHOTSDIR/home-$TODAY
    else
        echo "Todays backup already done"
    fi
fi

# make an external backup of the snapshot
# destination drive needs to be formatted as BTRFS ! 
if test -d "$EXTERNALSNAPSHOTSDIR"; then
    echo "using directory $EXTERNALSNAPSHOTSDIR for external backup."
    if [[ $LATEST_HOME_EXTERNAL -ne $TODAY ]]; then
        echo "Today is $TODAY and latest external backup is $LATEST_HOME_EXTERNAL copying data to external drive"
        # Update using latest external backup-date as reference to do the differential backup against
        btrfs send -p $LOCALSNAPSHOTSDIR/home-$LATEST_HOME_EXTERNAL $LOCALSNAPSHOTSDIR/home-$TODAY | btrfs receive $EXTERNALSNAPSHOTSDIR
    else
        if test -f "$EXTERNALSNAPSHOTSDIR/home-$TODAY"; then
            echo "External backup already up to date"
        else
            echo "Earlier versions not found, creating the first external backup to $EXTERNALSNAPSHOTSDIR"
            btrfs send $LOCALSNAPSHOTSDIR/home-$TODAY | btrfs receive $EXTERNALSNAPSHOTSDIR
        fi
    fi
else
    echo "External drive not found, is it mounted?"    
fi

external link to sample backup script

4 Likes

4 posts were split to a new topic: Why did the bash script get messed up in this post?

Timeshift can backup the user data (/home) folder, but it is not enabled by default. You also have to change your mounting points on the file system to be in line with Ubuntu’s method. I followed this guide to change my mounting points and regenerate the grub2 efi boot.

https://mutschler.eu/linux/install-guides/fedora-btrfs/

I don’t have an encrypted filesystem, so I didn’t need to mount LUKS like the writer of the article did. I just mounted the SATA (/dev/sda1) partition in /btrfs_pool and changed the fstab to reflect the new mounting points, while being more SSD friendly.

2 Likes

I know that Timeshift can be set to also include the home folder. I am thinking that is not set by default for size consideration, and making sure as much as your configuration as possible is what is saved. Though I don’t want to claim to know for sure on that front. I know a few of the “easy Arch” based distros come with it automatically, and you just need to change those settings.

I hope you find what you are looking for.