#!/bin/bash # # backs up home using restic and encryption # passphrases protected by GPG/Trezor hardware wallet function do_backup() { RUN_TIME="$(date +'%H:%M on %Y-%m-%d')" echo "Starting on-login backup at ${RUN_TIME}" echo "" restic -r "${BACKUP_DEST}" backup \ --compression "${COMPRESSION}" \ --exclude-file="${EXCLUDES_FILE}" \ --one-file-system \ "${BACKUP_SOURCE}" return $? } function read_enter() { # used in cases where we require input before continuing/exiting # ... but don't care what the input is echo "Please press Enter to exit..." read -r } set -x -o nounset -o pipefail # start vars, what to backup/exclude and where to log EXCLUDES_FILE="${HOME}/.restic_excludes" BACKUP_SOURCE="${HOME}" # misc options; compression / exit delay / retention period COMPRESSION="${COMPRESSION:-auto}" # default auto, one of [auto, off, max] EXIT_DELAY="${EXIT_DELAY:-3}" KEEP="${KEEP:-7d}" # define where to write backups - one at a time # double slashes for remote volumes are significant to separate host from path BACKUP_DEST="${BACKUP_DEST:-/raid1-evos/backups/restic}" PASS_NAME="${PASS_NAME:-restic/raid1-evos}" # PASS_NAME provides the path to the 'pass' object with the repo password # ie: 'pass restic/t7usb' would show the password; provided/backed by Trezor wallet through GPG # alts: # BACKUP_DEST="/mnt/t7usb/restic" # PASS_NAME="restic/t7usb" # BACKUP_DEST="sftp://zeta.jlay.dev//backup/restic" # uses SATA zvol # PASS_NAME="restic/zeta" # set restic specific vars; performance but also auth export RESTIC_READ_CONCURRENCY=8 # default 2 export RESTIC_PACK_SIZE=32 # default 16 MiB export RESTIC_PROGRESS_FPS=1 # export RESTIC_PASSWORD_FILE="/rust/backups/workstation/.restic_password_to_zeta_podvol" # redundant copy at /raid1-evos/backups/.workstation_restic_password_to_zeta_podvol set +x # ensure Trezor GPG agent is available/used for 'pass' export GNUPGHOME="${HOME}/.gnupg/trezor" echo "Getting repository password with 'pass'/GPG; check hardware wallet for verification" RESTIC_PASSWORD=$(pass "${PASS_NAME}") export RESTIC_PASSWORD # declare and assign separately to avoid masking rc # https://www.shellcheck.net/wiki/SC2155 # Check repository availability/consistency restic check -r "$BACKUP_DEST" --no-lock --quiet RESTIC_RC_CHECK=$? if (( RESTIC_RC_CHECK == 0 )); then # happy path - check of the destination passed, continue w/ backup echo -e "\nRestic repository is available and passed checks, proceeding" echo -e "\nCleaning up caches" restic cache --cleanup echo -e "\nCleaning backups older than $KEEP" restic -r "$BACKUP_DEST" forget --prune --keep-within "$KEEP" --quiet if do_backup; then echo -e "\nBackup succeeded!" else echo -e "\nBackup failed!" # require input before continuing/exiting read_enter fi else # empty line to separate our summary from the noise echo "" # unhappy path - check of the destination restic repo failed, and we didn't backup if (( RESTIC_RC_CHECK == 3 )); then echo "The repo doesn't seem to exist - cannot backup. Is '$BACKUP_DEST' mounted/available?" else echo "An unknown error occurred in checking '$BACKUP_DEST'." echo "Review output, no assurances on consistency with any backups. Storage medium failures possible." fi # require input before continuing/exiting read_enter fi echo "Exiting in $EXIT_DELAY seconds" sleep "${EXIT_DELAY}" unset RESTIC_PASSWORD