Automating backups on Mac OS X with Borg and cron

Photo by Skitterphoto from Pexels
My first attempt at automating borg backups had a 50% success rate. I setup Vorta on two similar mac mini’s, both running Mojave. I setup borgbase to notify me if no backup had been written for 5 days. I tested on the first machine and verified the backup was completed. I simply configured the second machine and forgot about it.
Five days later I received an email that no backups had been sent from one of the machines. I tried to start a backup from the Vorta client on the machine that failed and the error read “borg not found”. It seemed really odd that the borg binary was not found after a few successful backups. I did some minimal troubleshooting, but gave up after I read that one of the solutions was to deinstall/resinstall. I knew I wanted to add more logging to the backup so I decided to investigate initiating backups via cron.
I had run across a number of resources when i was looking at borg and borgmatic before I found Vorta. One of the resources I ran across was at roll urown. The author did a great job of documenting setting and providing a solution for both system and user backups on ubuntu. I’ve adapted much of what they wrote to work on the Mac.
The installation steps I’ve already covered here. For my use case, I followed the User Data Backup section from roll.urown.net. I created a directory to contain the backup script and the environment variables
$mkdir -p ~/.config/borg
$touch ~/.config/borg/vars.sh
$vi ~/.config/borg/vars.sh
Edit the file vars.sh as follows
#!/bin/bash
export BORG_REPO='notmrealreponame.repo.borgbase.com:repo'
export BORG_PASSPHRASE='notmyrealrepopassphrase'
#export BORG_RSH='ssh -i ~/.config/borg/ssh/id_ed25519'
#export BORG_BASE_DIR="${HOME}"
#export BORG_CONFIG_DIR="${HOME}/.config/borg"
#export BORG_CACHE_DIR="${HOME}/.cache/borg"
#export BORG_SECURITY_DIR="${HOME}/.config/borg/security"
#export BORG_KEYS_DIR="${HOME}/.config/borg/keys"
#export BORG_KEY_FILE="${HOME}/.config/borg/keys/${USER}.key"
Notice I’ve commented out many of the other variables. I’ve left my ssh key in my .ssh directory (the default place where ssh would find it). Some of these variables are useful if you have multiple users, but for what I’m doing, I don’t need them defined. Next is the actual backup script. This is largely borrowed from the borg documentation. I like how the author of roll.urown.net broke out the repo and pass phrase because it allows me to version my script in github without worry of storing the repo or password. I created a file to contain my script
$touch ~/.config/borg/borg-backup
$chmod 0700 ~/.config/borg/borg-backup
With the contents of the file “borg-backup” as follows:
#!/bin/bash
# Automated User Data Backup Script for BorgBackup
exec 1>>~/.config/borg/backup.log 2>&1
# Setup environment variables
# shellcheck source=vars.sh
source ~/.config/borg/vars.sh
# some helpers and error handling:
info() {
printf "\\n%s %s\\n\\n" "$( date )" "$*" >&2;
}
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM
info "Starting backup"
# Backup the most important directories into an archive named after
# the machine this script is currently running on:
# --filter AME \
# --filter AME \
/usr/local/bin/borg create \
--verbose \
--list \
--stats \
--show-rc \
--compression lz4 \
--exclude-caches \
\
::'{hostname}-{now}' \
~/Amazon\ Photos/Amazon\ Drive/ \
backup_exit=$?
info "Pruning repository"
# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
# archives of THIS machine. The '{hostname}-' prefix is very important to
# limit prune's operation to this machine's archives and not apply to
# other machines' archives also:
#/usr/local/bin/borg prune \
# --list \
# --prefix '{user}-{hostname}-' \
# --show-rc \
# --keep-daily 7 \
# --keep-weekly 4 \
# --keep-monthly 6 \
#
#prune_exit=$?
prune_exit=0
# use highest exit code as global exit code
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
if [ ${global_exit} -eq 1 ];
then
info "Backup and/or Prune finished with a warning"
fi
if [ ${global_exit} -gt 1 ];
then
info "Backup and/or Prune finished with an error"
fi
exit ${global_exit}
I’ve removed the “ — filter” option for now. I’ve also commented out the “prune” section. Both of these I’ll revisit after I have a better understanding of the output without filter and the impact of prune. Finally, you can see that I’m just backing up my amazon drive path.
The last step is to enable the job in cron. Run the following:
crontab -e
You will be presented with a blank file in your default editor. I added a line that looks like the following:
1 20 * * * ~/.config/borg/borg-backup
This tells cron to run this file 20:01 everyday.
After I set all this up, I tested by updating the line above (by running crontab -e ) and set it to a time that was just few minutes into the future. This worked and I left it alone for a few days.
Unfortunately, I discovered that my energy saver settings prevented cron from running and I again received notifications that borgbase was not receiving backups. After one final adjustment to the energy saver settings

I was able consistently run a backup with cron.
Next Steps
- I’d like to pull more out into config files, like options to borg as well as paths to backup.
- I want to consolidate logging. I’m looking at graylog to consolidate logging across my network.
- I want to receive alerts for failures. I’m looking at using prometheus for alert management.