-
Notifications
You must be signed in to change notification settings - Fork 0
Example: Backup a shared web server using Borg and rsync
Daniel Rudolf edited this page Feb 22, 2019
·
8 revisions
- Borg
bash
rsync
You can also backup your shared web server manually by simply running the script. The script is split up in two phases: First, it syncs all files of the shared web server using rsync
, and second, runs the actual backup using Borg. You can skip the rsync
phase by passing the --no-sync
option, or skip the actual Borg backup by passing the --no-borg
option.
#!/bin/bash
set -eE -o pipefail
# rsync target dir
RSYNC_SOURCE="my-server:~"
RSYNC_TARGET="$HOME/Backup/My server"
# Borg repository path
BORG_HOSTNAME="my-server"
BORG_REPOSITORY="$HOME/Backup/My server (Borg)"
# parse options
# be verbose, otherwise output nothing (except errors)
BORG="yes"
BORG_CREATE_PARAMS=( -v --stats --show-rc )
BORG_DELETE_PARAMS=( -v --stats --show-rc )
BORG_PRUNE_PARAMS=( -v --list --stats --show-rc )
RSYNC="yes"
RSYNC_PARAMS=( --stats -h )
if tty --quiet; then
BORG_CREATE_PARAMS+=( --progress )
BORG_DELETE_PARAMS+=( --progress )
RSYNC_PARAMS+=( --progress -v )
fi
while [ $# -gt 0 ]; do
case "$1" in
"-q"|"--quiet")
BORG_CREATE_PARAMS=()
BORG_DELETE_PARAMS=()
BORG_PRUNE_PARAMS=()
RSYNC_PARAMS=()
;;
"--no-sync")
RSYNC="no"
;;
"--no-borg")
BORG="no"
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
shift
done
# sync remote directory using rsync
if [ "$RSYNC" == "yes" ]; then
# prepare rsync target dir
if [ ! -e "$RSYNC_TARGET" ]; then
mkdir "$RSYNC_TARGET"
fi
if [ ! -d "$RSYNC_TARGET" ]; then
echo "Invalid rsync target dir: $RSYNC_TARGET" >&2
exit 1
fi
# sync remote directory
# if syncing fails, retry up to 3 times
for (( i=0 ; i <= 4 ; i++ )); do
RSYNC_STATUS=0
rsync -a -EAHX --numeric-ids --partial --delete "${RSYNC_PARAMS[@]}" \
"${RSYNC_SOURCE%/}/" "${RSYNC_TARGET%/}/" \
|| { RSYNC_STATUS=$?; true; }
[ $RSYNC_STATUS -ne 0 ] || break
sleep 300
done
[ $RSYNC_STATUS -eq 0 ] || exit $RSYNC_STATUS
fi
# create backup using Borg
if [ "$BORG" == "yes" ]; then
# prepare Borg repository
if [ ! -e "$BORG_REPOSITORY" ]; then
mkdir "$BORG_REPOSITORY"
borg init --encryption=repokey "$BORG_REPOSITORY"
fi
if [ ! -d "$BORG_REPOSITORY" ]; then
echo "Invalid repository: $BORG_REPOSITORY" >&2
exit 1
fi
# create backup (ignore warnings)
BORG_CREATE_STATUS=0
borg create "${BORG_CREATE_PARAMS[@]}" \
--compression=lz4 \
--exclude-caches --one-file-system \
"$BORG_REPOSITORY"::"$BORG_HOSTNAME-{now:%Y-%m-%dT%H:%M:%S}" \
"$RSYNC_TARGET" \
|| { BORG_CREATE_STATUS=$?; true; }
[ $BORG_CREATE_STATUS -lt 2 ] || exit $BORG_CREATE_STATUS
# remove checkpoints (ignore warnings)
BORG_DELETE_STATUS=0
if [ $BORG_CREATE_STATUS -eq 0 ]; then
BORG_CHECKPOINTS="$(borg list --short "$BORG_REPOSITORY" | grep -E '\.checkpoint(\.[0-9]+)?$' || true)"
if [ -n "$BORG_CHECKPOINTS" ]; then
xargs --max-args 1 --no-run-if-empty -I "%ARCHIVE%" -- \
borg delete "${BORG_DELETE_PARAMS[@]}" "$BORG_REPOSITORY"::"%ARCHIVE%" \
<<< "$BORG_CHECKPOINTS" \
|| { BORG_DELETE_STATUS=$?; true; }
[ $BORG_DELETE_STATUS -lt 2 ] || exit $BORG_DELETE_STATUS
fi
fi
# prune old backups (ignore warnings)
# keep everything within two days + 12 daily backups (= 2 weeks),
# 26 weekly backups (= 6 months), 24 monthly backups (= 2 years),
# 10 yearly backups
BORG_PRUNE_STATUS=0
borg prune "${BORG_PRUNE_PARAMS[@]}" \
"$BORG_REPOSITORY" --prefix "$BORG_HOSTNAME-" \
--keep-within=2d --keep-daily=12 \
--keep-weekly=26 --keep-monthly=24 \
--keep-yearly=10 \
|| { BORG_PRUNE_STATUS=$?; true; }
[ $BORG_PRUNE_STATUS -lt 2 ] || exit $BORG_PRUNE_STATUS
if [ $BORG_CREATE_STATUS -eq 1 ] || [ $BORG_DELETE_STATUS -eq 1 ] || [ $BORG_PRUNE_STATUS -eq 1 ]; then
exit 254
fi
fi