#!/bin/bash # # This is a simple backup script using duplicity. It's supposed to serve as a # starting point and to be adjusted to your system. # # Important steps: # - define a host "backup" in root's .ssh/config # - read the script and adjust to your needs # - export BORG_REPO in your environment or create a wrapper in $PATH that # does it for calls to borg (my preference). For details on the variable # see man borg set -e main() { if [[ $UID != 0 ]]; then exec sudo "$0" "$@" fi TMPDIR="$(mktemp -d "/tmp/${0##*/}.XXXXXX")" trap "rm -rf '${TMPDIR}'" EXIT TERM # if you want to encrypt the backups remove --no-encryption in the duplicity call # and uncomment the lines that contain PASSPHRASE #PASSPHRASE="randomstringhere" # these mountpoints will be excluded excludeMountpoints=( /tmp /sys /dev /proc /run /mnt/levant/nfs /media ) # these mountpoints will be included includeMountpoints=( / /boot /home /mnt/data ) # first line that matches wins IFS='' read -r -d '' excludeList < "$TMPDIR/exclude-list" echo "$excludeList_borg" > "$TMPDIR/exclude-list-borg" # save some data that's useful for restores local backupDataDir=/root/backup-data/ mkdir -p "$backupDataDir" fdisk -l > "$backupDataDir/fdisk" vgdisplay > "$backupDataDir/vgdisplay" pvdisplay > "$backupDataDir/pvdisplay" lvdisplay > "$backupDataDir/lvdisplay" lvdisplay > "$backupDataDir/lvdisplay" df -a > "$backupDataDir/df" findmnt -l > "$backupDataDir/findmnt" backup_borg / #local backupdir="$HOSTNAME-backup/full-backup" #backup_duplicity / "sftp://backup/$backupdir/" --exclude-filelist "$TMPDIR/exclude-list" #ssh backup "touch $backupdir/last-backup-timestamp" } backup_duplicity() { local src=$1 local dest=$2 shift 2 local -a options=() if [[ $(date +%d ) == '1' ]]; then # try to only run full backups on day 1 each month options+=(--full-if-older-than 2D) else # force a full backup once in a while options+=(--full-if-older-than 30D) fi #export PASSPHRASE HOME=/root duplicity \ -v5 \ --numeric-owner \ --volsize 250 \ --allow-source-mismatch \ --asynchronous-upload \ --no-encryption \ "${options[@]}" "$@" "$src" "$dest" HOME=/root duplicity --force remove-older-than 120D "$dest" #export PASSPHRASE="" } backup_borg() { local src=$1 borg create \ -v \ --numeric-owner \ --compression lz4 \ --stats \ --progress \ --exclude-from "$TMPDIR/exclude-list-borg" \ "::backup-$(date "+%Y%m%d-%H%M%S")" "$src" borg prune -v --keep-within 3m } ### support functions below ### ## # usage : in_array( $needle, $haystack ) # return : 0 - found # 1 - not found ## in_array() { local needle=$1; shift local item for item in "$@"; do [[ $item = "$needle" ]] && return 0 # Found done return 1 # Not Found } # same as in_array except 0 is returned if any item in haystack starts with needle in_array_startswith() { local needle=$1; shift local item for item in "$@"; do [[ "$needle" == "$item"* ]] && return 0 # Found done return 1 # Not Found } exclude_mountpoints() { local error=0 for fs in "${excludeMountpoints[@]}"; do excludeList+="- $fs/*"$'\n' excludeList_borg+="sh:$fs/*"$'\n' done while read line; do local mountpoint=$(echo "$line" | cut -d\ -f2 | sed 's#\040# #g;') if ! in_array $mountpoint "${includeMountpoints[@]}"; then if ! in_array_startswith "$mountpoint/" "${excludeMountpoints[@]/%//}"; then error=1 echo "Warning: mountpoint not excluded or included: $mountpoint" >&2 fi fi done