Bloat-Free System Backups

Vim is a component among other components. Don’t turn it into a massive application, but have it work well together with other programs.

Vim Reference Manual

In the last few weeks I have been doing a lot of system administration. For the first time in my life I own an actual PC, and I also have a home media server as well as a general home server that hosts this website amongst other things. With all this time having been invested into configuring these various systems along with the data migration from my now retired laptop to my PC, I felt it was about time to get an automated backup system working.

When doing research online, you’ll see a lot of talk about the 3-2-1 rule1, cloud storage providers, advanced backup tools, and a lot more slop that maybe makes sense in a high-risk enterprise environment, but which makes absolutely no sense for the average desktop user who simply wants to guard against hardware failure or other accidental forms of data loss.

To be clear, my specific usecase involves a simple backup of the home partition and system configurations of my desktop PC along with backups of my servers. I use my systems daily, so having a single daily backup is probably good enough, but just in case it takes me a while to notice that something has gone wrong I want to take a weekly backup as well.

Setting Up Storage

In order to go about doing this, I connected a random 2 TB SSD I had lying around to my OpenBSD server and configured it to act as an NFS. Since all my devices reside on the same network, I was able to restrict access to the NFS strictly to devices on the network, which was extremely straight-forwards to set up.

Exporting my drive over the network was a single line in /etc/exports:

/mnt/backups -alldirs -maproot=root -network=192.168.1.0 -mask=255.255.255.0

I additionally had to update the firewall rules to allow for network traffic to the various NFS ports, but since this traffic will be coming exclusively from the local network, I just decided to configure pf(4) to allow local traffic on all ports by adding the following line to my /etc/pf.conf:

pass in on egress proto { tcp, udp } from 192.168.1.0/24 to any

I also wanted to configure automatic mounting of the backup drive on my desktop PC so that I could inspect and manipulate the backups a bit more ergonomically. This took me down the rabbit-hole of autofs, which ended up solving my problem extremely easily. The entire configuration is just two lines, although it did take me longer to figure out than I’d like to admit:

# /etc/autofs/auto.master
/- /etc/autofs/auto.nfs

# /etc/autofs/auto.nfs
/mnt/backups -fstype=nfs,vers=3,noatime 192.168.1.185:/mnt/backups

Automating Backups

With the NFS setup out of the way, I could then move on to the actual backing-up of data. Taking inspiration from OpenBSD’s changelist(5), I created two files: /etc/backups.d/include and /etc/backups.d/exclude. These files contain newline-separated file names of files and directories that should be included or excluded from backups.

Here’s an example of what my initial include file looked like:

/etc/autofs
/etc/backup.d
/etc/cron.daily
/etc/cron.weekly
/etc/cryptsetup-keys.d
/etc/crypttab
/etc/doas.conf
/etc/dracut.conf
/etc/dracut.conf.d
/etc/fstab
/etc/hostname
/etc/hosts
/etc/locale.conf
/etc/login.defs
/etc/man.conf
/etc/ntpd.conf
/etc/pam.d
/etc/papersize
/etc/rc.conf
/etc/rc.local
/etc/rc.shutdown
/etc/resolv.conf
/etc/resolvconf.conf
/etc/security
/etc/turnstile
/etc/wpa_supplicant
/etc/xbps.d
/home

The next step was setting up my backup scripts. Since I wanted both daily and weekly backups I decided to make use of the /etc/cron.daily and /etc/cron.weekly directories that are supported by my cron dæmon of choice, but you could of course set these up as regular cronjobs.

So, at /etc/cron.daily/backup I created the following script to backup my system as per my include and exclude files. The entire script consists of just two command invocations! In my case I chose to use openrsync(1) instead of the traditional rsync(1) because rsync is slop now and I have moral qualms with the use and production of clanker slop, but you can easily swap in standard rsync(1) if you really want to.

#!/bin/sh

openrsync -Aamr --delete --exclude-from=/etc/backup.d/exclude \
	--include-from=/etc/backup.d/include --numeric-ids \
	--include='*/' --exclude='*' \
	/ /mnt/backups/desktop.daily/
sync -f /mnt/backups/desktop.daily

I also placed a nearly identical version of the above script into /etc/cron.weekly, with the obvious substitutions of desktop.daily with desktop.weekly.

And yep, that’s it. That single two-line script along with the basic NFS configuration is all it took to set up easily-configurable backups of my home desktop machine, with similar strategies possible for backing up my home and media servers. All bloat-free and slop-free, just how I like it.