Creating Backups with borgbackup and Maintaining them with Systemd

After major data loss, I made a plan: Backups!
I reorganized my hard drive, which now contains a separate partition only for backups. This will be mounted when needed. After a little preliminary search i decided on Borg - it is simple to use, and deduplicating.

Automation is the key.

Weekly backups, initiated by a systemd timer.
I used this article as a crutch, with two notable exceptions:

  • my backup partition is encrypted; my backups are not
  • the partition is owned by root and I do backups as root; I don't think this is "making a mess of things"

Everything that follows is just an example, and a simple one at that.
Reading the borg documentation - a lot more is possible.

Before starting with backups & automation, the borg backup repositories have to be initiated:

sudo su -
cd /mnt/backup # or whereever they are on your system
borg init root-system.bup
borg init var-www.bup
borg init data.bup

These three repos represent actual partitions. I prefer to have a separate backup for each filesystem. I'm not saying borg has to be used like this; this is my choice. Also the extension .bup is just my choice. Those become actual directories in the cwd.

Here's an example script using the above three repositories. Please note the excluded directories, it is the only way to backup a live system, and a sane choice for many other situations (because too much constantly changing & useless data otherwise).
The example is for a desktop machine with a graphical session running, sending desktop notifications for each step (also see this article); my other machine does not have a graphical desktop, but the script is essentially the same, just pruned.

sh
#!/bin/bash exec 2>&1 # needed to see all info in systemd journal? date="$(date +%Y%m%d%H%M)" me="${0##*/}" # same as basename $0 mountpoint="/mount/point" sep="===============================================" function notify { sudo -u username DISPLAY=":0.0" XAUTHORITY="/home/username/.Xauthority" DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus" notify-send "$1" "$2" } function exit_mount_error { echo "$mountpoint is NOT mounted - cannot continue - please investigate!" notify "$me" "$mountpoint is NOT mounted - cannot continue - please investigate!" exit 1 } mount -v "$mountpoint" mount | grep " on $mountpoint" || exit_mount_error cd "$mountpoint"/desktop-backups notify "$me" "root-system.bup::$date\nBackup started" echo -e "$sep\nroot-system.bup::$date Backup started" borg break-lock root-system.bup borg create --stats --info --exclude-caches --one-file-system -C zlib -e /proc -e /tmp -e /run -e /sys -e /media -e /dev -e /home/username/.cache root-system.bup::"$date" / notify "$me" "var-www.bup::$date\nBackup started" echo -e "$sep\nvar-www.bup::$date Backup started" borg break-lock var-www.bup borg create --stats --info --exclude-caches --one-file-system -e /var/www/somestuff -C zlib \ var-www.bup::"$date" /var/www notify "$me" "data.bup::$date\nBackup started" echo -e "$sep\ndata.bup::$date Backup started" borg break-lock data.bup borg create --stats --info --exclude-caches --one-file-system -C zlib \ -e /data/tmp-yaourt -e /data/iso data.bup::"$date" /data for backup in root-system var-www data; do notify "$me" "Checking $backup.bup\non $date" echo -e "$sep\nList $backup.bup:" borg list "$backup.bup" echo "Checking: borg check --info --save-space $backup.bup" borg check --info --save-space "$backup.bup" done echo -e "$sep\nFinished. Syncing & Unmounting." notify "$me" "Finished. Syncing & Unmounting." sync df -hl . cd / umount -v "$mountpoint"

Try running the script manually first.

When that works, it's time to automate!

Systemd service, saved as /etc/systemd/system/borgbackup.service:

cfg
[Unit] Description=Borg Backup [Service] Type=simple Nice=19 IOSchedulingClass=2 IOSchedulingPriority=7 ExecStart=/path/to/borgbackup.sh

For the Nice and IOScheduling values, read man systemd.exec.

Systemd timer, saved as /etc/systemd/system/borgbackup.timer:

cfg
[Unit] Description=Borg Backup Timer [Timer] WakeSystem=false OnCalendar=Sat *-*-* 16:00:00 RandomizedDelaySec=1h # older systemd versions might not have this. no matter. [Install] WantedBy=timers.target

Now issue sudo systemctl enable borgbackup.timer and sudo systemctl start borgbackup.timer; then systemctl list-timers to see when it is next scheduled.
Another manual run with sudo systemctl start borgbackup.service might be prudent, and have a good look at what's happening with journalctl -b|grep borgbackup or journalctl -f.


Addition

I had a minor accident this morning - deleted a rather important file: ~/.xinitrc. First time to feel the joy and benefit of having backups!
A small note: because the initiation of the fuse filesystem in userspace depends on something that was initiated in my .xinitrc (dbus I guess), borg mount errored out. But borg mount really is just a convenience utility, everything is still accessible and I quickly found the file with borg list REPO::archive | grep '.xinitrc' and used borg extract to restore it. Phew!