Skip to content

Instantly share code, notes, and snippets.

@novoid
Created August 29, 2020 10:30
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save novoid/21dd371d4489fe550c0168ddbb4039f1 to your computer and use it in GitHub Desktop.
Save novoid/21dd371d4489fe550c0168ddbb4039f1 to your computer and use it in GitHub Desktop.
Backup shell script using rsnapshot (rsync)
#!/bin/sh
## My one and only backup script for the future :-)
## Uses rsnapshot.
##
## Please do read this blog article about that script: https://Karl-Voit.at/2020/08/29/vkbackup/
##
## ---------------------------------------------------
##
## Initial setup:
## 1. install and setup http://rsnapshot.org/
## 2. install and setup https://github.com/novoid/appendorgheading
## 3. install and setup notify-send (I'm using Debian, so it's "sudo apt install notify-send")
## 4. install and setup grml-crypt from https://grml.org/ (makes LUKS much easier to use)
## 5. replace "user" with your user name.
## 6. adapt the complete configuration setting below with BACKUPNAME, UUID, REFILE_ORGFILE, REFILE_HEADING
## 7. adapt all paths to tools and log files and such: "hostname", ...
## 8. create and check mountpoints
## 9. create and check LUKS target partitions: grml-crypt from https://grml.org/ is awesome!
## 10. add the executable flag to this script: chmod +x vkbackup
## 11. this shell script has minimal error detection: so please make sure you understand the script and
## test it with test data before you use it in a real-life scenario.
## 12. make a test-run and test restore ;-)
##
## ---------------------------------------------------
##
## Adding a new backup disk:
## 1. Find out UUID of LUKS device and add to script
## 2. Define unique BACKUPNAME, an refile-target org mode file name and heading titla (not ID) and add to script
## 3. Adapt /home/user/archive/backup/hostname/rsnapshot_${BACKUPNAME}.conf
## 4. Adapt /home/user/archive/backup/hostname/rsnapshot_exclude_file_${BACKUPNAME}.txt
##
## ---------------------------------------------------
##
## Run a backup:
## 1. Plug in physical HDD (which is LUKS encypted)
## 2. start "vkbackup" as root
## 3. enter LUKS passphrase
## 4. <wait for end of backup run> (pay attention to the desktop notification)
## 5. if no error appeared, umount was successful and HDD can be unplugged
##
## Creates log output in: /home/user/log/vkbackup-hostname-${BACKUPNAME}.log
##
## ---------------------------------------------------
##
## Manually mounting: (using grml-crypt; if you don't use grml-crypt, you have to look up all the steps yourself)
## 1. grml-crypt start /dev/disk/by-uuid/${UUID} "${MOUNTPOINT}"
##
## ---------------------------------------------------
##
## Manually umounting: (using grml-crypt; if you don't use grml-crypt, you have to look up all the steps yourself)
## 1. grml-crypt stop ${MOUNTPOINT}
##
set -o nounset
set -o errexit
if [ -b /dev/disk/by-uuid/12345678cc-8103-4900-abcde-987654321 ]; then
BACKUPNAME="1TBbackup" ## shortname of the backup (better omit spaces and special characters)
UUID="12345678cc-8103-4900-abcde-987654321" ## UUID of the backup disk volume
REFILE_ORGFILE="misc.org" ## Org mode file to re-file to
REFILE_HEADING="Backup: 1TBbackup (Off-site-backup)" ## Org mode heading title to re-file to
elif [ -b /dev/disk/by-uuid/ababababab-1234-4b39-8233-9182737465 ]; then
BACKUPNAME="4TBbackup"
UUID="ababababab-1234-4b39-8233-9182737465"
REFILE_ORGFILE="misc.org"
REFILE_HEADING="Backup: My 4T Bbackup"
## TEMPLATE:
# elif [ -b /dev/disk/by-uuid/ ]; then
# BACKUPNAME=""
# UUID=""
# REFILE_ORGFILE="misc.org"
# REFILE_HEADING=""
else
echo "ERROR: No known UUID for backup found."
echo "Check script: ${0}"
exit 2
fi
## ======================================================================= ##
## ======================================================================= ##
## ======================================================================= ##
LOGFILE="/home/user/log/vkbackup-${BACKUPNAME}.log"
MOUNTPOINT="/mnt/backup"
STARTTIME_IN_ORG_TIMESTAMP="<$(date '+%Y-%m-%d %a %H:%M')>"
NOW_IN_ISO_TIMESTAMP=$(/bin/date +%Y-%m-%dT%H.%M.%S)
NOW_IN_ISO_DATESTAMP=$(/bin/date +%Y-%m-%d)
## Mounting LUKS backup disk: (and asking for passphrase)
mkdir -p "${MOUNTPOINT}"
mount | grep "${MOUNTPOINT}" || grml-crypt start /dev/disk/by-uuid/${UUID} "${MOUNTPOINT}" || exit 1
## Before-backup statistics:
script_start=$(date +%s)
echo "================================================================================"
echo
echo "begin: $(date)"
df -h | egrep 'Filesystem|luks|crypt|sda1|backup'
echo
df_before=$(df -h | awk '{ print " | " $1 " | " $2 " | " $3 " | " $4 " | " $5 " | " $6 " |" "\t" }' | \
sed 's/Mounted |/Mounted |\n |---------------------------------------------------|/')
## Running the actual backup command:
echo "starting backup command ..."
echo
nice -n 19 rsnapshot -c /home/user/archive/backup/hostname/rsnapshot_${BACKUPNAME}.conf alpha 2>&1 > "${LOGFILE}" || \
sudo -u user /usr/local/bin/appendorgheading --title "rsnapshot run resultet in an error, see file:${LOGFILE}" --level 1
echo
echo "end: $(date)"
## After-backup statistics:
echo
echo "Situation after backup:"
echo
df -h | egrep 'Filesystem|luks|crypt|sda1|backup'
df_after=$(df -h | awk '{ print " | " $1 " | " $2 " | " $3 " | " $4 " | " $5 " | " $6 " |" "\t" }' | \
sed 's/Mounted |/Mounted |\n |---------------------------------------------------|/')
script_end=$(date +%s)
script_runtime=$((script_end-script_start))
script_HMS=$(date -u -d @${script_runtime} +"%T")
echo
echo "Running times (in hh:mm:ss)"
echo "| Total | ${script_HMS} |"
echo
ENDTIME_IN_ORG_TIMESTAMP="<$(date '+%Y-%m-%d %a %H:%M')>"
## Generate Org mode result block:
TEMPFILE=$(mktemp)
echo > "${TEMPFILE}"
echo "#+BEGIN_SRC emacs-lisp" >> "${TEMPFILE}"
echo "(my-org-refile \"${REFILE_ORGFILE}\" \"${REFILE_HEADING}\")" >> "${TEMPFILE}"
echo "#+END_SRC" >> "${TEMPFILE}"
echo "" >> "${TEMPFILE}"
echo "- logfile: [[file:${LOGFILE}][${LOGFILE}]]" >> "${TEMPFILE}"
echo "- Backup target UUID: ${UUID}" >> "${TEMPFILE}"
echo >> "${TEMPFILE}"
echo "- \"df -h\" before backup:" >> "${TEMPFILE}"
echo >> "${TEMPFILE}"
echo "${df_before}" >> "${TEMPFILE}"
echo >> "${TEMPFILE}"
echo "- \"df -h\" after backup:" >> "${TEMPFILE}"
echo >> "${TEMPFILE}"
echo "${df_after}" >> "${TEMPFILE}"
echo >> "${TEMPFILE}"
echo >> "${TEMPFILE}"
body=$(cat "${TEMPFILE}")
rm "${TEMPFILE}"
sudo -u user /usr/local/bin/appendorgheading \
--title "${STARTTIME_IN_ORG_TIMESTAMP}--${ENDTIME_IN_ORG_TIMESTAMP} vkbackup: ${BACKUPNAME} took ${script_HMS} (HH:MM:SS)" \
--output /home/user/org/inbox.org \
--level 1 \
--section "${body}" \
--filecontent "${LOGFILE}" \
--nodaily
## Notify user and wait for one minute before umounting LUKS device:
sudo -u user notify-send "${BACKUPNAME} finalized 🔜 unmounting" "`/bin/date '+%Y-%m-%dT%H:%M:%S'`" &
echo "wait for one minute and do grml-crypt stop ..."
sleep 1m ; grml-crypt stop ${MOUNTPOINT}
sudo -u user notify-send "${BACKUPNAME} finished and umounted" "`/bin/date '+%Y-%m-%dT%H:%M:%S'`" -u critical &
echo "vkbackup ${BACKUPNAME} ended."
#end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment