I Configure BorgBackup and Borgmatic

15 hours ago 3

This article outlines how I configure BorgBackup and borgmatic on my machines.

Tested on

  • MacBook Air M2
  • macOS Ventura 13.4.1
  • borgmatic 1.7.12 (MacPorts)
  • moreutils 0.67_1 (MacPorts)

borgmatic and moreutils are also available on Homebrew.

Unlike systemd, launchctl doesn’t provide integration a syslog-like service. (I guess Apple expects you to use Console instead)

Apple’s unified logging is unreliable and in many tests I have had messages disappearing, even when manually testing with the syslog standard C library function. For example, events disappear for some users when viewing them through log stream.

If you want to redirect borgmatic’s standard out and standard error to a $PREFIX/var/log/borgmatic/{stdout,stderr}.log file, I recommend wrapping borgmatic in a helper script like the following, which I have put in $HOME/.local/bin/borgmatic_timestamp.sh:

#!/bin/bash # https://apple.stackexchange.com/a/406097 set -e set -o pipefail # Substitute /opt/local/bin/borgmatic and /opt/local/bin/ts # for the correct path if you don't use MacPorts /opt/local/bin/borgmatic create prune -v2 \ 2> >(/opt/local/bin/ts -m '[%Y-%m-%d %H:%M:%S] -' 1>&2) \ 1> >(/opt/local/bin/ts -m '[%Y-%m-%d %H:%M:%S] -')

Create a LaunchAgent in $HOME/Library/LaunchAgents/net.yourdomain.yourprogram.plist. Substitute any $USER string for your username:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>net.yourdomain.yourprogram</string> <key>ProgramArguments</key> <array> <string>/Users/$USER/.local/bin/borgmatic_timestamp.sh</string> </array> <key>UserName</key> <string>$USER</string> <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>0</integer> </dict> <key>StandardOutPath</key> <string>/Users/$USER/.local/var/log/borgmatic.stdout.log</string> <key>StandardErrorPath</key> <string>/Users/$USER/.local/var/log/borgmatic.stderr.log</string> <key>EnvironmentVariables</key> <dict> <key>HOME</key> <string>/Users/$USER</string> </dict> </dict> </plist>

Activate using

launchctl bootstrap "gui/$EUID" "$HOME/Library/LaunchAgents/net.yourdomain.yourprogram.plist"

This .plist file configures borgmatic to run at the beginning of every hour. If you want to run borgmatic immediately, you can kickstart it using

launchctl kickstart gui/$EUID/net.yourdomain.yourprogram.plist

This blog post is pretty helpful in explaining the new bootstrap syntax compared to the legacy load syntax using launchctl.

There’s one caveat with launchctl, when comparing it to systemd. systemd provides extensive support for process isolation and hardening. launchctl only provides limited support. It’s not possible, for example, to run a LaunchAgent and give it read-only access to the filesystem.

Here’s a shortcut that you can use in fish to extract a file (in this example, /etc/profile):

borgmatic extract \ --repository "$YOUR_REPOSITORY" \ --archive ( borgmatic --no-color rlist --short --repository "$YOUR_REPOSITORY" | fzf ) \ --path /etc/profile

This example uses fzf to select a specific archive. That way you can get a macOS Time Machine-like date selection, as a TUI.

Run the following command to show all keys for all repositories in a printable text format:

borgmatic key export --paper

You can print this file and recover your keys if you lose it. I recommend storing your paper key export in a safe location. Someone can use your paper keys and decrypt all your backups.

You can stream a tar ball containing backed up data using export-tar like so:

borgmatic export-tar \ --repository $REPOSITORY \ --archive $ARCHIVE \ --path $PATH_YOU_WANT_TO_TEST \ --destination - | \ gtar --compare --file=- -C /

This uses GNU tar (installed with MacPorts as gnutar) to compare the files in the piped tar ball to what’s stored on your filesystem.

BorgBackup has a repository and archive consistency check command. With borgmatic, you can set this up and run automatically in arbitrary intervals with the checks configuration key.

You can also perform a spot check and borgmatic supports this in version 1.8.10.

If you would like to run a sampling test yourself, you can follow these steps:

  1. Decide on your sample size N and sample N files from your file system.
  2. Export a tar archive with these files from the latest archive with borg export-tar repositories.
  3. Run tar --compare on your file system and check the tar file contents.
  4. Count number of differences in files to check whether backup and recovery process works correctly.

To sample, for example, 10 random files from your file system, you can combine the sort and awk command in the terminal:

find / -type f -print0 | \ sort --random-sort --zero-terminated | \ awk 'BEGIN {RS="\0"} {print $0} NR==10{exit}'

Running find on your file system can take a long time. You can speed this up by only checking one directory. Here, find only looks at files in your home directory:

find $HOME -type f -print0 | \ sort --random-sort --zero-terminated | \ awk 'BEGIN {RS="\0"} {print $0} NR==10{exit}'

You may also want to exclude files that are too new to be included in a recent BorgBackup archive. If your last backup ran one day ago, exclude files younger than 24 hours using -ctime:

find $HOME -type f -ctime +1 -print0 | \ sort --random-sort --zero-terminated | \ awk 'BEGIN {RS="\0"} {print $0} NR==10{exit}'

Here’s what the find manual says on -ctime:

-ctime n

File’s status was last changed less than, more than or exactly n*24 hours ago. […]

From the same find manual, here’s the format for numeric arguments, such as for -ctime:

+n for greater than n, -n for less than n, n for exactly n.

You can also exclude files that you aren’t backing up in BorgBackup to avoid false-positives.

If you use macOS, you can use the mdfind command instead of find:

mdfind -onlyin $HOME -0 \ 'kMDItemContentModificationDate < $time.now(-86400)' | \ sort --random-sort --zero-terminated | \ awk 'BEGIN {RS="\0"} {print $0} NR==10{exit}'

Now that you have selected 10 files, export a tar file from your latest BorgBackup archive. You can achieve this using borgmatic export-tar:

borgmatic export-tar \ --repository $YOUR_REPOSTIORY \ --archive latest \ --path $PATHS

In bash, $PATHS should be an array containing pairs of --path and the path itself. Here’s how to do that with a combination of mapfile and the awk command:

mapfile -d '' PATHS < <(find $HOME -type f -ctime +1 -print0 | \ sort -z -R | \ awk 'BEGIN {RS="\0"} {printf("--path%c%s%c", 0, $0, 0)} NR==10 {exit} ')

With mdfind on macOS, you can run this instead:

mapfile -d '' PATHS < <(mdfind -onlyin $HOME -0 \ 'kMDItemContentModificationDate < $time.now(-86400)' | \ sort --random-sort --zero-terminated | \ awk 'BEGIN {RS="\0"} {printf("--path%c%s%c", 0, $0, 0)} NR==10 {exit} ')

Now run export-tar on these files:

borgmatic export-tar \ --repository $YOUR_REPOSITORY \ --archive latest \ "${PATHS[@]}" \ --destination $PWD/archive.tar

Compare the contents using the tar --compare command:

tar --compare --file archive.tar --verbose --directory /

This tar invocation lists each file in the archive and tells you whether there are any differences to the files on your file system. tar also checks whether file permissions or timestamps are different.

You can then estimate the total amount of differences in your file system based on how many of the 10 files in the archive.tar file were different.

I use Time Machine to back up my MacBook computers. Even though Time Machine is fast and supports incremental backups, it doesn’t work well with offsite backups. With BorgBackup, I can reuse my configuration between my NixOS machines and my MacBook computers and perform backups on-site and off-site.

Instead of preferring one method over the other, I choose to use both BorgBackup and Time Machine. Further, if you follow the 3-2-1 Backup Rule, having your backups on different backup media and off-site gives you peace of mind.

For creating off-site backups with BorgBackup, I use BorgBase.

Read Entire Article