BorgBackup automation scripts
Distributed, encrypted, deduplicated and compressed backups
Published on May 16, 2022.I have been using BorgBackup for a while now to backup my machines to external drives and a NAS. For more convenience I created a set of scripts to automate this process.
The first part is a script doing the actual backup process by calling borg. This is inspired by the example script in the documentation.
#!/bin/sh # ~/bin/backup-borg # Helper script for automated borg backups. # BACKUP_PATH, BACKUP_EXCLUDES, BORG_REPO and BORG_PASSPHRASE # should already be set in environment from calling script! if [[ -z "$BACKUP_PATH" ]]; then echo "Please set BACKUP_PATH before calling" exit 1 fi if [[ -z "$BACKUP_EXCLUDES" ]]; then echo "Please set BACKUP_EXCLUDES before calling" exit 1 fi if [[ -z "$BORG_REPO" ]]; then echo "Please set BORG_REPO before calling" exit 1 fi # $BORG_PASSPHRASE is allowed to be empty # some helpers and error handling: info() { printf "\n%s\n%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: borg create \ --verbose \ --list \ --filter E \ --stats \ --progress \ --show-version \ --show-rc \ --compression lz4 \ --exclude-caches \ $BACKUP_EXCLUDES \ \ ::'{hostname}-{now}' \ $BACKUP_PATH 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: borg prune \ --verbose \ --list \ --prefix '{hostname}-' \ --progress \ --show-version \ --show-rc \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 6 prune_exit=$? info "Compacting repository" # Also do a compact after each prune, to free space borg compact \ --verbose \ --progress \ --show-version \ --show-rc compact_exit=$? # use highest exit code as global exit code bp_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit )) global_exit=$(( bp_exit > compact_exit ? bp_exit : compact_exit )) if [ ${global_exit} -eq 1 ]; then info "Backup finished with a warning" fi if [ ${global_exit} -gt 1 ]; then info "Backup finished with an error" fi exit ${global_exit}
Run the following commands to create a new repository and export it's key. This key needs to be stored somewhere safe, along with the password you set in the first command.
borg init --encryption=repokey /path/to/repo
borg key export /path/to/repo key-file-name
I have multiple different borg repositories on various disks and machines. For each combination of backup input and output location, I created another script, calling the previous one with the proper values for location, excludes and repository password.
#!/bin/sh # ~/bin/backup-root-extern export BORG_REPO=/mnt/backup/borg-linux-root export BORG_PASSPHRASE='REDACTED' export BACKUP_PATH=/ export BACKUP_EXCLUDES=" \ --exclude=/home/* \ --exclude=/var/cache/* \ --exclude=/var/tmp/* \ --exclude=/media/* \ --exclude=/mnt/* \ --exclude=/dev/* \ --exclude=/proc/* \ --exclude=/sys/* \ --exclude=/tmp/* \ --exclude=/run/* \ --exclude=/lost+found/* \ " backup-borg backup_exit=$? exit ${backup_exit}
For convenience, I created yet another script that does all the backups into the same locations / machine.
#!/bin/sh # ~/bin/backup-extern sudo backup-root-extern root_exit=$? sudo backup-home-extern home_exit=$? sudo backup-data-extern data_exit=$? # use highest exit code as global exit code rh_exit=$(( root_exit > home_exit ? root_exit : home_exit )) global_exit=$(( rh_exit > data_exit ? rh_exit : data_exit )) if [ ${global_exit} -eq 1 ]; then echo "One or Multiple Backups finished with a warning" fi if [ ${global_exit} -gt 1 ]; then echo "One or Multiple Backups finished with an error" fi exit ${global_exit}
Which can easily be combined with the following script, which tries to mount one of the external backup disks I rotate through.
#!/bin/bash # ~/bin/mount-backup ( sudo mount -U xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/backup -t ext4 || sudo mount -U xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/backup -t ext4 ) && echo ok
I can now simply plug in a backup disk and run "mount-backup && backup-extern" to run a new backup.
I'm also using these scripts for Cloud backups.