Let The Borgs Do It
Today I finally finished my migration from my old Hetzner root server, which still ran my MailCow mailserver, to my netcup VPS. And since it's been quite a few years since I last set up my borg backup solution on Hetzner, I thought it would be a good idea to update and document my backup system.
So in this blog post, I will teach you how to:
- set up a borg backup repo on another (file) server
- automate your entire backup with borgmatic & bash scripts
- do a partial or full restore from your backups
Since I use Ubuntu Server on my VPS, the guide will focus on that. If you use a different Linux / OS, please check the installation instructions of borg and borgmatic. Since both programs are python-based, they run on practically any Linux distribution.
Automatic BackUp with Borgmatic
Requires
🤖 Borg Backup
🚀 Borgmatic
📦️ Hetzner Storage Box (or equivalent provider with borg support)
While borg can backup to any SSH capable server, it will gain a significant performance boost, if the target server also has borg installed. The quote from borg backup states:
Off-site backups
Borg can store data on any remote host accessible over SSH. If Borg is installed on the remote host, significant performance gains can be achieved compared to using a network file system (sshfs, NFS, …).
To prevent permission and file access problems, I will set up everything as root.
So after connecting to your server, start with sudo -s to switch into root.
Setup
Install borgbackup with fuse3
Guide
# Install all dependencies
apt install python3 python3-dev python3-pip python3-virtualenv \
libacl1-dev \
libssl-dev \
liblz4-dev libzstd-dev libxxhash-dev \
build-essential pkg-config libfuse3-dev fuse3
# Install borgbackup with fuse3
pipx install borgbackup[pyfuse3]
# Check if /root/.local/bin is in your path with
echo $PATH
# If it is not in your $PATH
# Follow on-screen instruction to add it to $PATH
Install borgmatic
# Install borgmatic
pipx install borgmatic
# Check borgmatic installation
borgmatic --version
# Create default config.yaml
borgmatic config generate
# /etc/borgmatic/config.yaml
Setup Borg Repository
- Create a SSH Key with
ssh-keygen -f ~/.ssh/KEY_NAME(no password) - Add
~/.ssh/KEY_NAME.pubto storage servers~/.ssh/authorized_keysssh-copy-id -i ~/.ssh/KEY_NAME user@host
- Set up
~/.ssh/configentry for storage server - Test ssh connection to storage server to make sure it works
- Disconnect from the storage server again
- Initialize borg repo with
borg init --encryption=repokey --remote-path=borg-1.4 ssh://uXXXXX@uXXXXX.your-storagebox.de:23/./borg-repository(Hetzner Storage Box example) - Choose a strong encryption passphrase
- Backup repo key with
borg key export /PATH/TO/REPO > /PATH/TO/KEY
Setup Borgmatic with CONFIG.yaml
- Open the config.yaml with
nano /etc/borgmatic/config.yaml - Choose
source_directories:.- These are the folders you want to backup (
/opt/docker/for example)
- These are the folders you want to backup (
- Choose the repository
path:you set up with borglabel:(optional)
- Copy / Paste your strong
encryption_passphrase: - Set retention policy with
keep_daily:(default: 7) - Test the connection with
borgmatic -i
BackUp
Backup Script for Docker Container
If you want to backup all your docker container in /opt/docker/:
- Create a folder to store all your backup instructions / logs
- Create a
logs_oldfolder inside that folder to store log files - Create a new script with
nano /PATH/TO/BACKUP_FOLDER/docker_backup.sh - Paste the following content into it
#!/bin/env bash
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nBacking up log files.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Make a copy of the logs files into logs_old folder
cp /PATH/TO/BACKUP_FOLDER/docker_backup.log /PATH/TO/BACKUP_FOLDER/logs_old/
cp /PATH/TO/BACKUP_FOLDER/borgmatic.log /PATH/TO/BACKUP_FOLDER/logs_old/
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nBacked up log files to logs_old.\nTruncating logs.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Empty the log files
truncate -s 0 /PATH/TO/BACKUP_FOLDER/docker_backup.log
truncate -s 0 /PATH/TO/BACKUP_FOLDER/borgmatic.log
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nTruncated log files.\nStopping docker container.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Run docker compose down on any compose.yml in any /opt/docker/FOLDER
for i in $(find /opt/docker/ -type f -name compose.yml); do
/usr/bin/docker compose -f $i down &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
done
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nStopped all docker containers.\nStarting borgmatic backup.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Run borgmatic to transfer your source folders to your storage server
/root/.local/bin/borgmatic create --verbosity 1 --list --stats &>> /PATH/TO/BACKUP_FOLDER/borgmatic.log
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nFinished borgmatic backup.\nStarting containers.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Run docker compose up -d on any compose.yml in any FOLDER inside /opt/docker/
for i in $(find /opt/docker/ -type f -name compose.yml); do
/usr/bin/docker compose -f $i up -d &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
done
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nStarted all docker containers.\n.Starting borgmatic prune.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Clean up old archives from your borg repo according to your retention policy
/root/.local/bin/borgmatic prune --list --stats >> /PATH/TO/BACKUP_FOLDER/borgmatic.log
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nBorg repo pruned.\n.Starting borgmatic compacting.\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
# Free up disk space from the removed archives
/root/.local/bin/borgmatic compact --progress &>> /PATH/TO/BACKUP_FOLDER/borgmatic.log
CURRENTDATE=`date +"%Y-%m-%d %T"`
echo -e $CURRENTDATE '\nBorg repo compacted.\n.Backup finished!\n' &>> /PATH/TO/BACKUP_FOLDER/docker_backup.log
Basic log rotation
To automate the log file clean up
- Create a new script with
nano /PATH/TO/BACKUP_FOLDER/clean_logs.sh - Open the new file with
nano /PATH/TO/BACKUP_FOLDER/clean_logs.sh - Copy the following script into the file
#!/bin/env bash
# Deletes all log files in logs_old folder
rm -rf /PATH/TO/BACKUP_FOLDER/logs_old/*.log
Initial BackUp
- Modify paths in
docker_backup.sh - Modify paths in
clean_logs.sh - Make the backup script executable with
chmod +x docker_backup.sh - Make the clean_logs script executable with
chmod +x clean_logs.sh - Run your first backup manually with
./docker_backup.sh &- Depending on the amount of data, this can take quite a while
- You can check the logs during the backup with
tail -f XXX.log - Check the newly created borg repo archive with
borgmatic -i
Setup cronjob
With a cronjob, we can have our scripts run automatically at specific intervalls. To better understand the cron schema, use a cronjob generator.
- Start cronjob edit with
crontab -eand copy & paste the two codes at the end 0 2 * * * /bin/bash /PATH/TO/docker_backup.sh- Run backup every night at 02:00
0 0 * * 0 /bin/bash /PATH/TO/clean_logs.sh- Delete old logs every sunday at 00:00
Maintenance
- Regularly check the borg repo and logs
- Make sure old archives are pruned
- Make sure old logs are deleted from the
logs_oldfolder
- Regularly check your storage server
- Check storage space and traffic (if not unlimited)
Restore from Backups
Borg and Borgmatic make it very easy to quickly transfer the backed up files and folders back to your server, in case you need to restore some or all of them.
Mount your backups into a folder
- Create a folder to mount into with
mkdir /mnt/MOUNT - Mount your borg repo with
borgmatic mount --mount-point /mnt/MOUNT - Copy files and folders as needed into a temporary folder
- To prevent errors from bugs, I consider it safer to first copy my stuff into a local folder on my server
- Stop the container you want to restore
- Delete
/opt/docker/FOLDERas needed - Move backup from temp. to
/opt/docker/ - Start your container again
- Unmount with
borgmatic umount --mount-point /mnt/MOUNT
Extract a single file or folder
If you want to transfer a single file or folder from your borg repo
# Search the latest archive for a file or folder
borgmatic --find FILE_OR_FOLDER_NAME --archive latest
# Extract a file or folder
borgmatic extract --archive latest --path PATH/TO/FOLDER_OR_FILE --destination /PATH/TO/DEST
# will extract to current folder without --destination
# Parent folders will be included, so files & folder will be at
# /PATH/TO/DEST/PATH/TO/FOLDER_OR_FILE
# --archive can also choose a specific archive
# Check the available archives with
borgmatic -l
# Use the archive name instead of latest
Full Restore (for migration / in emergencies)
If you want to transfer your entire borg backups
- Create a temp. folder with
mkdir -pv /tmp/borgmatic_tmp - Extract the latest backup archive with
borgmatic extract --archive latest --destination /tmp/borgmatic_tmp - Copy required files and folders
- Delete temp. folder with
rm -rf /tmp/borgmatic_tmp
Additional Information
With borgmatic, you are not limited to a single config.yaml. You can easily copy the /etc/borgmatic/config.yaml and change the source_directories:, path:, etc.
If you want to use another config.yaml and create a second script, just add --config /PATH/TO/SECOND_CONF.yaml to any borgmatic command. (borgmatic --config /PATH/TO/SECOND_CONF.yaml -l, for example)
That's all for today. I hope this guide made data backup and restoration easier for some of you.
- ← Previous
All Things SSH