2025-01-31 BorgBackup for the laptop and the server

A few days ago I mentioned the rsync-based backup script I use to copy data from the server to the laptop.

rsync-based backup script

The backup script that makes backups of my laptop (including the backup from the server) to external disks is different, however.

My actual backup uses external disks. I have two of them. One of them is always at the office. Every now and then (not often enough!) I make a backup to the external disk I have at hand and then I carry it to the office and bring the other one back. That is, the laptop and the two external disks are never in the same location.

The two external disks I use are "known backup disks". When I plug them in, BorgBackup immediately starts making a backup. I discussed this setup back in 2017.

back in 2017

I'm just going to repost the stuff and I don't think there have been any significant changes.

Run commands and create files as root.

Either use `sudo` for every command you run, or use `sudo su` once and do everything as root. No matter how you do it, the danger zone awaits!

`/mnt/backup`

Create the mount point on the laptop:

mkdir /mnt/backup

`/etc/fstab`

Any disk labeled “Backup” will be mounted as `/mnt/backup`:

LABEL=Backup /mnt/backup auto nosuid,nodev,nofail,noauto,x-gvfs-show 0 0

`/etc/backups/40-backup.rules`

Install a symlink to this file:

ln -s /etc/backups/40-backup.rules \
      /etc/udev/rules.d/40-backup.rules

The file content:

ACTION=="add", SUBSYSTEM=="bdi", DEVPATH=="/devices/virtual/bdi/*", TAG+="systemd", ENV{SYSTEMD_WANTS}="automatic-backup.service"

This makes sure that the service `automatic-backup` starts whenever an external disk gets plugged into the laptop.

`/etc/backups/automatic-backup.service`

Install a symlink to this file:

ln -s /etc/backups/automatic-backup.service \
      /etc/systemd/system/automatic-backup.service

The service does nothing except start the `run.sh` shell script.

[Service]
Type=oneshot
ExecStart=/etc/backups/run.sh

`/etc/backups/backup.disks`

The `run.sh` below runs for every external disk plugged in. It's important to only make backups to known backup disks, however.

The known backup disks are identified by their `uuid` in the `backup.disks` file.

To list the disk labels and their `uuid`:

lsblk -o+uuid,label

Add the `uuid` to the `/etc/backups/backup.disks` file.

This is the content of the file identifying my backup disks, for example:

# generate using: lsblk -o+uuid,label
7c478832-5d7f-43d3-9b79-20cfc67fb0e6
bb1c034e-dd21-48e7-a496-1b95685a094d
156cf4df-aa58-421e-b3d0-583fe6fdff4a

If you create your copy of the file, your uuids will be different!

When you run `lsblk -o+uuid,label` you'll also see the device itself. In my case, that's `/dev/sdb`. Create a BorgBackup repository on the new disk, mount it, create the directory and initialize the repository.

When initializing the repository, you're asked for a passphrase. You will need it for the `run.sh` script.

mount /dev/sdb /mnt/backup
mkdir /mnt/backup/borg-backups
borg init --encryption=repokey --progress /mnt/backup/borg-backups/backup.borg
umount /mnt/backup

Make sure the disk has the correct label! You can do this from the command-line but I used Disks.

Disks

`/etc/backups/run.sh`

Now we're ready for the actual script. It checks whether a known backup disk is mounted under `/mnt/backup` and if so, it creates a new archive in the repository.

Don’t forget to search for `BORG_PASSPHRASE` and change it to whatever you used when you ran `borg init` above!

Hide the passphrase from everybody else and to make it executable:

chmod 0700 run.sh

This the content of the shell script:

#!/bin/bash -ue

# The udev rule is not terribly accurate and may trigger our service before
# the kernel has finished probing partitions. Sleep for a bit to ensure
# the kernel is done.
#
# This can be avoided by using a more precise udev rule, e.g. matching
# a specific hardware path and partition.
sleep 5

#
# Script configuration
#

# The backup partition is mounted there
MOUNTPOINT=/mnt/backup

# This is the location of the Borg repository
TARGET=$MOUNTPOINT/borg-backups/backup.borg

# This is the file that will later contain UUIDs of registered backup drives
DISKS=/etc/backups/backup.disks

# Find whether the connected block device is a backup drive
for uuid in $(lsblk --noheadings --list --output uuid)
do
        if grep --quiet --fixed-strings $uuid $DISKS; then
                break
        fi
        uuid=
done

if [ ! $uuid ]; then
        echo "No backup disk found, exiting"
        exit 0
fi

echo "Disk $uuid is a backup disk"
partition_path=/dev/disk/by-uuid/$uuid
# Mount file system if not already done. This assumes that if something is already
# mounted at $MOUNTPOINT, it is the backup drive. It won't find the drive if
# it was mounted somewhere else.
(mount | grep $MOUNTPOINT) || mount $partition_path $MOUNTPOINT
drive=$(lsblk --inverse --noheadings --list --paths --output name $partition_path | head --lines 1)
echo "Drive path: $drive"

#
# Create backups
#

# Set BORG_PASSPHRASE or BORG_PASSCOMMAND somewhere around here, using export,
# if encryption is used.
export BORG_PASSPHRASE="*secret*"

# No one can answer if Borg asks these questions, it is better to just fail quickly
# instead of hanging.
export BORG_RELOCATED_REPO_ACCESS_IS_OK=no
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no

echo Backup melanobombus
borg create \
     --stats \
     --one-file-system \
     --compression lz4 \
     --show-version \
     --exclude /proc \
     --exclude /dev \
     --exclude /sys \
     --exclude /tmp \
     --exclude /mnt \
     --exclude /media \
     --exclude /home/alex/.cache \
     --exclude /root/.cache \
     --exclude /var/cache \
     --exclude /var/log \
     --exclude /run/user/1000/gvfs \
     $TARGET::{utcnow}-{hostname} \
     /

echo Prune melanobombus
borg prune \
     --stats \
     --list \
     --show-rc \
     --keep-daily    7 \
     --keep-weekly   4 \
     --keep-monthly  6 \
     --glob-archives '*-{hostname}' \
     $TARGET

# Just to be completely paranoid
sync

if [ -f /etc/backups/autoeject ]; then
    umount $MOUNTPOINT
    hdparm -Y $drive
fi

if [ -f /etc/backups/backup-suspend ]; then
    systemctl suspend
fi

Check the logs!

Check the log while the backup is being written:

journalctl --follow --unit automatic-backup

Make sure the backup disk is identified correctly and look at the sizes of the archives. If they're too small, check whether the archives contain the right files!

​#Backup ​#Administration

Good point. I think in my case it doesn’t matter because I don’t use the disk space for anything else (and surely Borg will reuse it). But who knows. Your situation might be different.