#!/bin/bash ############# # VARIABLES # ############# # Script-wide variables and commands. You only need to configure the first one, and possibly the last. readonly SCRIPT_DIR="/path/to/script/dir" readonly LOG_DIR="${SCRIPT_DIR}/backup-logs" readonly DATETIME="$(date '+%Y-%m-%d_%H:%M:%S')" readonly BACKUP_LOG="${LOG_DIR}/backup-log_"${DATETIME}".log" readonly LOG_RETENTION="14" set -o errexit set -o nounset set -o pipefail exec 3<&1 4<&2 trap "exec 2<&4 1<&3" 0 1 2 3 # If moreutils is not installed, comment out or delete the next line and uncomment the one after exec > >(tee >(ts "%Y-%m-%d_%H:%M:%S" > "${BACKUP_LOG}")) 2>&1 # exec > >(tee "${BACKUP_LOG}") 2>&1 # Rsync Manifest 01 Variables # Configure variables from here... readonly RSYNC_SOURCE_01="/path/to/dir/to/backup-01" readonly RSYNC_DEST_01="/path/to/dir/to/backup/to-01" readonly RSYNC_MANIFEST_01="${SCRIPT_DIR}/path/to/manfiest-file-01.conf" readonly RSYNC_RETENTION_DAYS_01="9" # ...to here readonly RSYNC_DEST_PATH_01="${RSYNC_DEST_01}/${DATETIME}" readonly RSYNC_LATEST_LINK_01="${RSYNC_DEST_01}/latest" # Rsync Manifest 02 Variables # Configure variables from here... readonly RSYNC_SOURCE_02="/path/to/dir/to/backup-02" readonly RSYNC_DEST_02="/path/to/dir/to/backup/to-02" readonly RSYNC_MANIFEST_02="${SCRIPT_DIR}/path/to/manfiest-file-02.conf" readonly RSYNC_RETENTION_DAYS_02="9" # ...to here readonly RSYNC_DEST_PATH_02="${RSYNC_DEST_02}/${DATETIME}" readonly RSYNC_LATEST_LINK_02="${RSYNC_DEST_02}/latest" # Restic Backup 01 Variables. Configure all accordingly. readonly RESTIC_PASSWORD_01="${SCRIPT_DIR}/path/to/restic-password-01.file" readonly RESTIC_SOURCE_01="/path/to/dir/to/backup-01" readonly RESTIC_REPO_01="/path/to/restic/repo-01" readonly RESTIC_RETENTION_DAYS_01="7" readonly RESTIC_RETENTION_WEEKS_01="4" readonly RESTIC_RETENTION_MONTHS_01="6" readonly RESTIC_RETENTION_YEARS_01="1" readonly RESTIC_TAG_01="tag01" readonly RESTIC_TAG_02="tag02" readonly RESTIC_EXCLUDES_01="${SCRIPT_DIR}/path/to/excludes-file-01" # Restic Backup 02 Variables. Configure all accordingly. readonly RESTIC_PASSWORD_02="${SCRIPT_DIR}/path/to/restic-password-02.file" readonly RESTIC_SOURCE_02="/path/to/dir/to/backup-02" readonly RESTIC_REPO_02="/path/to/restic/repo-02" readonly RESTIC_RETENTION_DAYS_02="7" readonly RESTIC_RETENTION_WEEKS_02="4" readonly RESTIC_RETENTION_MONTHS_02="6" readonly RESTIC_RETENTION_YEARS_02="1" readonly RESTIC_TAG_03="tag03" readonly RESTIC_TAG_04="tag04" readonly RESTIC_EXCLUDES_02="${SCRIPT_DIR}/path/to/excludes-file-02" ################### # RSYNC SCRIPT(S) # ################### # Creates the backup directory mkdir -p "${RSYNC_DEST_01}" # -avP will tell rsync to run in archive mode, be verbose, keep partial files if interrupted, and show progress rsync -avP --delete --prune-empty-dirs --include-from="${RSYNC_MANIFEST_01}" \ "${RSYNC_SOURCE_01}/" \ --link-dest "${RSYNC_LATEST_LINK_01}" \ "${RSYNC_DEST_PATH_01}" # This will update the latest hardlink rm -rf "${RSYNC_LATEST_LINK_01}" ln -s "${RSYNC_DEST_PATH_01}" "${RSYNC_LATEST_LINK_01}" # The hacky fix for the NFS destination timestamp bug touch "${RSYNC_DEST_PATH_01}"/timestamp.fix # This will prune excess version folders. cd "${RSYNC_DEST_01}" rm -rf `ls -t | tail -n +"${RSYNC_RETENTION_DAYS_01}"` # CD backup to script dir to reset for next steps cd - # Remove the rest of the rsync script if you are only running on source -> destination # Or, copy, paste, and configure as many times as needed. Remember to also update variables up above mkdir -p "${RSYNC_DEST_02}" rsync -avP --delete --prune-empty-dirs --include-from="${RSYNC_MANIFEST_02}" \ "${RSYNC_SOURCE_02}/" \ --link-dest "${RSYNC_LATEST_LINK_02}" \ "${RSYNC_DEST_PATH_02}" rm -rf "${RSYNC_LATEST_LINK_02}" ln -s "${RSYNC_DEST_PATH_02}" "${RSYNC_LATEST_LINK_02}" touch "${RSYNC_DEST_PATH_02}"/timestamp.fix cd "${RSYNC_DEST_02}" rm -rf `ls -t | tail -n +"${RSYNC_RETENTION_DAYS_02}"` cd - #################### # RESTIC SCRIPT(S) # #################### # --p points to the password file, -r points to the restic repo path restic backup --verbose \ -p "${RESTIC_PASSWORD_01}" \ -r "${RESTIC_REPO_01}" \ --tag "${RESTIC_TAG_01}" --tag "${RESTIC_TAG_02}" \ --exclude-caches \ --exclude-file="${RESTIC_EXCLUDES_01}" \ "${RESTIC_SOURCE_01}" # Now we forget snapshots and prune data for the same tags in the repo restic forget --prune --tag tag1,tag2 \ -p "${RESTIC_PASSWORD_01}" \ -r "${RESTIC_REPO_01}" \ --keep-daily "${RESTIC_RETENTION_DAYS_01}" \ --keep-weekly "${RESTIC_RETENTION_WEEKS_01}" \ --keep-monthly "${RESTIC_RETENTION_MONTHS_01}" \ --keep-yearly "${RESTIC_RETENTION_YEARS_01}" # Finally, we verify the integrity of the repo restic check \ -p "${RESTIC_PASSWORD_01}" \ -r "${RESTIC_REPO_01}" # Remove or copy and paste as needed. Remember: multiple sources and tags can go to the same repo. restic backup --verbose \ -p "${RESTIC_PASSWORD_02}" \ -r "${RESTIC_REPO_02}" \ --tag "${RESTIC_TAG_03}" --tag "${RESTIC_TAG_04}" \ --exclude-caches \ --exclude-file="${RESTIC_EXCLUDES_02}" \ "${RESTIC_SOURCE_02}" restic forget --prune --tag tag3,tag4 \ -p "${RESTIC_PASSWORD_02}" \ -r "${RESTIC_REPO_02}" \ --keep-daily "${RESTIC_RETENTION_DAYS_02}" \ --keep-weekly "${RESTIC_RETENTION_WEEKS_02}" \ --keep-monthly "${RESTIC_RETENTION_MONTHS_02}" \ --keep-yearly "${RESTIC_RETENTION_YEARS_02}" restic check \ -p "${RESTIC_PASSWORD_02}" \ -r "${RESTIC_REPO_02}" ############## # TIDYING UP # ############## # Clean up log files older than 14 days find "${LOG_DIR}" -mtime +"${LOG_RETENTION}" -type f -delete # End of script message in log echo > >(tee >(echo "$(ts "%Y-%m-%d_%H:%M:%S") Backup Script Complete" >> "${BACKUP_LOG}"))