#!/bin/bash ############################ # LOGGING & ERROR HANDLING # ############################ # Ensure you set the SCRIPT_DIR variable correctly as the error handling will not catch it # Change the LOG_RETENTION if you wish for more or less. readonly SCRIPT_DIR="/path/to/script/dir" readonly LOG_DIR="${SCRIPT_DIR}/backupLogs" readonly DATETIME="$(date '+%Y-%m-%d_%H:%M:%S')" readonly BACKUP_LOG="${LOG_DIR}/backupLog_"${DATETIME}".log" readonly LOG_RETENTION="14" exec 3<&1 4<&2 trap "exec 2<&4 1<&3" 0 1 2 3 exec > >(tee >(ts "%Y-%m-%d_%H:%M:%S" > "${BACKUP_LOG}")) 2>&1 set -eEuo pipefail # Uncomment the below to debug the script # set -x # trap 'err_report' ERR # function err_report() { # sleep 5 # curl \ # -T "${BACKUP_LOG}" \ # -H "Filename: backupLog_"${DATETIME}".log" \ # -H prio:high \ # -H "Title: Backup Failed on ${HOSTNAME}" \ # ntfyUser:ntfyPassword@ntfyDomain/ntfyTopic # } ################ # RSYNC SCRIPT # ################ # 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}/rsyncManifest" 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" # 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}"` ################# # RESTIC SCRIPT # ################# # Configure all but first and last accordingly. readonly RESTIC_PASSWORD_01="${SCRIPT_DIR}/.resticPassword" 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" # If you prefer a keep last retention policy, comment out the above 4 and uncomment the below and configure # readonly RESTIC_RETENTION_KEEP_LAST_01="2" readonly RESTIC_TAG_01="tag01" readonly RESTIC_TAG_02="tag02" readonly RESTIC_EXCLUDES_01="${SCRIPT_DIR}/resticExcludes" # --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 --verbose --tag "${RESTIC_TAG_01}","${RESTIC_TAG_02}" \ -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}" # If using a keep last retention policy, comment out the above forget command and uncomment the below # restic forget --prune --verbose --tag "${RESTIC_TAG_01}","${RESTIC_TAG_02}" \ # -p "${RESTIC_PASSWORD_01}" \ # -r "${RESTIC_REPO_01}" \ # --keep-last "${RESTIC_RETENTION_KEEP_LAST_01}" # Finally, we verify the integrity of the repo restic check \ -p "${RESTIC_PASSWORD_01}" \ -r "${RESTIC_REPO_01}" ############## # TIDYING UP # ############## # Clean up log files older than 14 days # find "${LOG_DIR}" -mtime +"${LOG_RETENTION}" -type f -delete find "${LOG_DIR}"/*.log -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}")) # sleep 5 # curl \ # -T "${BACKUP_LOG}" \ # -H "Filename: backupLog_"${DATETIME}".log" \ # -H prio:low \ # -H "Title: Backup Succeeded on ${HOSTNAME}" \ # ntfyUser:ntfyPassword@ntfyDomain/ntfyTopic