Backups With Borg

I use Ansible and a dotfiles manager called yadm to store changes I make to my system so that I can rebuild my machine easily whenever I want to. This takes care of programs I use and their settings, plus system settings such as thinkfan config, plasma desktop tweaks and emacs lisp scripts.

I also use git for many of my content repos for software I write/contribute to, creative works I write and wikis/blogs I manage - including this one. This takes care of persisting my files in the cloud so that I can easily restore a working environment on any computer whenever I need.

But this is only the case for files I want to store in git and only whenever I’m ready to commit and push them into a remote repo. So what about the files I’ve work in progress and haven’t pushed or files I simply don’t want in those repos such as photos, videos and some documents?

In this post I’ll document my use of Borg, a backup tool and how I try to make sure I’ve captured those files so I can restore them if I need to.

Installing Borg

I already have my ansible script installing Borg, I use pacman (Arch linux package manager).

I could have done this manually with $ sudo pacman -Syu borg and I’m pretty sure it would be available in most package managers. Doing so should install most of the dependencies too.

Other options include building from source and using pip install. Borg is python based so it should run on most operating systems and architectures as long as the dependencies are available.

Setting Up the Borg Repo

I need a directory to initialise a borg repo and I have an mSata drive in my T430 so I’m going to use this for all backups. I should have a remote backup repo too but for now I’ll concentrate on getting a local one set up.

I have a mount to the disk and a directory there for the borg repo, I initialise the repo only once and set up the encryption keys and passcode. There are many ways to encrypt the borg repo and I’ve decided to use BLAKE2b with keyfile. I’ll have to make sure the keyfile isn’t readable by anyone else.

When I initialise the repo it will ask me for a passphrase. I’ll need to store this somewhere and use it whenever I make a backup. Again there are many ways of storing and using secrets like this. For my purposes I’m going to store it in a keepass database.

First I’ll create a keepass file and generate a passphrase to use:

$ keepassxc-cli create -k /secret/path/for/key /path/for/kdbx
Enter password to encrypt database (optional): 
Successfully created new database.

I edit the file permissions for the created key and db so that only I can read and write them.

$ chmod 0400 /secret/path/for/key /path/for/kdbx

Then I generate the passphrase that will be used for the borg repo

$ keepassxc-cli add -p --no-password -k /secret/path/for/key /path/for/kdbx borg
Enter password for new entry: 
Successfully added entry borg.

Finally I’ll initialise the borg repo using this passphrase for the key.

$borg init --encryption=keyfile-blake2 /path/to/repo
Enter new passphrase: 
Enter same passphrase again: 
Do you want your passphrase to be displayed for verification? [yN]: n

By default repositories initialized with this version will produce security
errors if written to with an older version (up to and including Borg 1.0.8).

If you want to use these older versions, you can disable the check by running:
borg upgrade --disable-tam /path/to/repo

See https://borgbackup.readthedocs.io/en/stable/changes.html#pre-1-0-9-manifest-spoofing-vulnerability for details about the security implications.

IMPORTANT: you will need both KEY AND PASSPHRASE to access this repo!
Use "borg key export" to export the key, optionally in printable format.
Write down the passphrase. Store both at safe place(s).

Configuring the Backups

I am using a wrapper for borg called Borgmatic which consists mainly of a conig.yml file. To generate this file I ran:

$ generate-borgmatic-config --destination ~/path/to/config.yml
$ chmod 0600 ~/path/to/config.yml

I won’t go over all the settings, reading through the file is quite obvious - it’s well documented and I could use man borg or man borgmatic to quickly reference further info. The source directories I’ve just set to my home dir and the repository to the path where I initialised the borg repo.

I’ve added my own preferences throughout the file like using an exclude files and listing paths such as /*/.cache. It’s this file I’ll need to change when I want to configure anything to do with my backups and I imagine I’ll be tweaking it periodically to exclude and include paths as I install new software etc.

To help me with the tweaking process I’ve set the exclude_if_present so that if I have a dir with .noborg in then the backup should see that and not back up that dir.

The config file breaks down borg commands into vars and within the storage section I have set the encryption details. Using encryption_passcommand allows me to use a command to access the passphrase for the repo. I set this in keepass file and I use a cli tool to access that password using the key and db I created earlier.

encryption_passcommand:  keepassxc-cli show -a Password --no-password
-k  /secret/path/for/key /path/for/kdbx borg

Timing and Automated Backups

The other important set of variables within the borgmatic is the retention section. This is where the time periods are set to define what should be pruned out of the repo. Again I’ll probably tweaks this over time and I’m going to start out backing up every hour, retaining a copy for each hour over the previous 24h, one copy per day for the past 7 days, one copy per week for the past 4 weeks and one copy per month for the past 6 months.

To run the backups I am using systemd so I created a borgmatic.service file:

[Unit]
Description=borgmatic backup
Wants=network-online.target
After=network-online.target
#ConditionACPower=true

[Service]
Type=oneshot
#running as user tom, permission denied for systemd-inhibit so using runuser in command instead
#User=tom 

# Lower CPU and I/O priority.
Nice=19
CPUSchedulingPolicy=batch
IOSchedulingClass=best-effort
IOSchedulingPriority=7
IOWeight=100

Restart=no
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
# doesn't support this (pre-240 or so), you may have to remove this option.
LogRateLimitIntervalSec=0

# Delay start to prevent backups running during boot.
ExecStartPre=sleep 1m
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent
interrupting scheduled backup" runuser tom -c 'borgmatic --syslog-verbosity 1 --config=/full/path/to/borgmatic/config.yml'

In the comments notice I want to run the service as a my own user but my user doesn’t have permission to run systemd-inhibit and so I can’t use the setting User=tom instead I use runuser in the ExecStart command.

I also have a borgmatic.timer for this, I’ve created it so it will run 5 minutes after booting up and every hour after that.

[Unit]
Description=Run borgmatic backup

[Timer]
Persistent=true
OnBootSec=5min
OnUnitActiveSec=1h

[Install]
WantedBy=timers.target

I then enable these and start the timer.

$ sudo systemctl enable borgmatic.service
$ sudo systemctl enable borgmatic.timer
$ sudo systemctl start borgmatic.timer
$ sudo systemctl daemon-reload

Listing the Repo

To view the backups taken in a repo I run the following:

borgmatic --config /home/tom/.config/borgmatic/config.yml list

Security

I’ve gone to some effort to secure the backup process by using keys and passphrases. I’ve stored my passphrase in a password manager but it could have also been stored in a key managers and it’s on my todo list to see if there’s a more secure way such as KDE kwallet-query, though the password manager I have chosen is cross platform as is borg.

I have backups of my keys on usb stick and have put my passphrases in a safe place.

I have encrypted keys again and other files containing references to the keys and I have stored these in my favourite dot files manager. My home directory is also encrypted at rest so it won’t be easy to access these files should my laptop get stolen for example.

I’m not certain that I have covered everything to secure my backups but at least I believe I have made it difficult for anyone who wants to access this data.

Conclusion

This was quite a challenging set up but now that it’s backing my files up frequently I feel a bit happier about being able to roll back files to a previous state even if they’re not in source control.

I need to review and experiment with querying the repo next and maybe do a dry run recovery so I know that it works end to end - it’s no use having a backup if you can’t recover it.

Also having the backup on my local machine isn’t really a backup, I need to have that backup also being written to a remote repo somewhere.

I’ll need to tween the configs and expand the include/exclude paths and files to backup as I progress. I think Borg is a great bit of software, it compresses and dedupes to make for small repos and has some interesting querying options to explore.