156 lines
4.2 KiB
Bash
Executable file
156 lines
4.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# shellcheck disable=SC2317,SC2086,SC2181,SC2129,SC2002,SC2088
|
|
#
|
|
# restic backup using rclone as the transport
|
|
# - designed to be cron/timer driven, uses repo key on disk (security warning)
|
|
#
|
|
# (a) set up and test the rclone remote
|
|
# (b) run the restic init first-time repo prep
|
|
# (c) prepare the encryption key and excludes files, chmod 0600
|
|
# (d) uses ~/.mailrc to send backup log/report via `mail` cmd
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
##
|
|
## TEMPLATE - NEEDS ALL SYSTEM SPECIFIC VARIABLES CONFIGURED
|
|
##
|
|
|
|
# restic exit codes:
|
|
# Exit status is 0 if the command was successful
|
|
# Exit status is 1 if there was a fatal error
|
|
# (no snapshot created).
|
|
# Exit status is 3 if some source data could not be read
|
|
# (incomplete snapshot created).
|
|
|
|
# restic init:
|
|
# restic -r rclone:remote: init
|
|
|
|
# restic excludes format examples:
|
|
# Downloads/
|
|
# VirtualBox**
|
|
# .config/**Cache*
|
|
# .config/*/sessions
|
|
# .config/restic/xyzzy.txt
|
|
# .thunderbird/**/*.msf
|
|
# .xsession-errors*
|
|
|
|
# cloud provider expired SSL cert hack
|
|
RCLONE_NO_CHECK_CERTIFICATE=true
|
|
export RCLONE_NO_CHECK_CERTIFICATE
|
|
|
|
# email and log settings
|
|
MAILTO="user@example.com"
|
|
LOGDIR="/home/user/.logs"
|
|
TIMESTAMP=$(date +%Y-%m-%d_%H%M)
|
|
MAILSUB="restic backup: ${TIMESTAMP}"
|
|
LOGFILE="${LOGDIR}/restic_${TIMESTAMP}.log"
|
|
|
|
# have `mail` add timestamps to dead.letter
|
|
DEAD="~/dead.letter-${TIMESTAMP}"
|
|
export DEAD
|
|
|
|
# restic settings
|
|
REPO="rclone:remote:"
|
|
RSRC="/home/user"
|
|
# encryption key, plaintext, chmod 0600
|
|
RKEY="/home/user/.config/restic/xyzzy.txt"
|
|
# excludes, chmod 0600
|
|
EXCL="/home/user/.config/restic/excludes.txt"
|
|
# snapshots to keep
|
|
KEEP=10
|
|
|
|
# trap our signals
|
|
function error_exit {
|
|
echo "Trapped a kill signal, exiting."
|
|
exit 99
|
|
}
|
|
trap error_exit SIGHUP SIGINT SIGTERM
|
|
|
|
# this may be needed for non-packaged binaries
|
|
# (e.g. using newer restic on older LTS distro)
|
|
function check_restic() {
|
|
echo "Checking restic..."
|
|
# get installed version
|
|
_LOCAL=$(restic version 2>/dev/null | awk '{print $2}'; exit ${PIPESTATUS[0]})
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "Unable to get installed restic version" >> "${LOGFILE}"
|
|
exit 1
|
|
fi
|
|
|
|
# get latest version, strip leading "v" (v1.55.1 -> 1.55.1)
|
|
_REMOTE=$(curl -s "https://api.github.com/repos/restic/restic/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')
|
|
_REMOTE=${_REMOTE#v}
|
|
|
|
# bash doesn't see versions as numbers, but as strings
|
|
if [[ "${_LOCAL}" != "${_REMOTE}" ]]; then
|
|
echo "Upgrade restic - installed ${_LOCAL}, latest ${_REMOTE}" >> "${LOGFILE}"
|
|
else
|
|
echo "Installed restic is the latest - ${_LOCAL}" >> "${LOGFILE}"
|
|
fi
|
|
}
|
|
# uncomment as needed
|
|
#check_restic
|
|
|
|
# begin timestamp
|
|
echo "== ${TIMESTAMP} ==" >> "${LOGFILE}"
|
|
|
|
# remove stale locks
|
|
restic -r "${REPO}" \
|
|
--password-file="${RKEY}" \
|
|
unlock >> "${LOGFILE}"
|
|
_EC=$?
|
|
|
|
# create a new snapshot
|
|
if [[ $_EC -eq 0 ]]; then
|
|
restic --quiet -r "${REPO}" \
|
|
backup --no-scan \
|
|
--password-file="${RKEY}" \
|
|
--exclude-file="${EXCL}" \
|
|
"${RSRC}" >> "${LOGFILE}"
|
|
_EC=$?
|
|
else
|
|
echo "Non-zero exit from restic unlock: $_EC" >> "${LOGFILE}"
|
|
fi
|
|
|
|
# prune older snapshots
|
|
if [[ $_EC -eq 0 ]]; then
|
|
restic --quiet -r "${REPO}" \
|
|
forget --prune --keep-last ${KEEP} \
|
|
--password-file="${RKEY}" >> "${LOGFILE}"
|
|
_EC=$?
|
|
if [[ $_EC -ne 0 ]]; then
|
|
echo "Non-zero exit from restic forget: $_EC" >> "${LOGFILE}"
|
|
fi
|
|
else
|
|
echo "Non-zero exit from restic backup: $_EC" >> "${LOGFILE}"
|
|
fi
|
|
|
|
# check reposotory health
|
|
restic --cleanup-cache -r "${REPO}" \
|
|
check --password-file="${RKEY}" >> "${LOGFILE}"
|
|
_EC=$?
|
|
if [[ $_EC -ne 0 ]]; then
|
|
echo "Non-zero exit from restic check: $_EC" >> "${LOGFILE}"
|
|
else
|
|
# list available snapshots
|
|
restic -r "${REPO}" \
|
|
snapshots -c --password-file="${RKEY}" >> "${LOGFILE}"
|
|
# generate stats about repo
|
|
restic -r "${REPO}" \
|
|
stats --mode=files-by-contents --password-file="${RKEY}" >> "${LOGFILE}"
|
|
restic -r "${REPO}" \
|
|
stats --mode=raw-data --password-file="${RKEY}" >> "${LOGFILE}"
|
|
fi
|
|
|
|
# end timestamp
|
|
_NOW=$(date +%Y-%m-%d_%H%M)
|
|
echo "== ${_NOW} ==" >> "${LOGFILE}"
|
|
|
|
# ~/.mailrc needs to be configured
|
|
cat "${LOGFILE}" | mail -A mailprovider -s "${MAILSUB}" "${MAILTO}"
|
|
|
|
# remove older logfiles
|
|
find "${LOGDIR}" -type f -name restic\* -mtime +30 -delete
|
|
|
|
exit 0
|
|
|