Downloads configurable directories from uberspace users (and also other SSH-accessible server) and encrypts them with GnuPG. Can automatically delete older backups.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

uberspace-backup.sh 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #!/usr/bin/env bash
  2. # SPDX-FileCopyrightText: 2019 Max Mehl <mail [at] mehl [dot] mx>
  3. # SPDX-License-Identifier: GPL-3.0-or-later
  4. ########################################################################
  5. #
  6. # Saves specific files and directories from a remote server via SSH.
  7. # Provides easy shortcuts for Uberspace.de hosts.
  8. # README.md provides more details.
  9. #
  10. ########################################################################
  11. CURDIR=$(dirname "$(readlink -f "$0")")
  12. if [ ! -e "$CURDIR"/config.cfg ]; then echo "Missing config.cfg file. Edit and rename config.cfg.sample"; exit 1; fi
  13. source "$CURDIR"/config.cfg
  14. if [ ! -e "${HOSTS}" ]; then echo "Missing hosts file. Please set a correct value of HOSTS= in your config file. Current value: ${HOSTS}"; exit 1; fi
  15. if [ ! -z "${SSH_KEY}" ]; then
  16. SSH_KEY_ARG="-i ${SSH_KEY}"
  17. else
  18. # defaults
  19. SSH_KEY_ARG=""
  20. SSH_KEY=~/.ssh/id_rsa
  21. fi
  22. # Get current date
  23. DATE=$(date +"%Y-%m-%d_%H-%M")
  24. LOG="$CURDIR"/backup.log
  25. function trim {
  26. sed -r -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g'
  27. }
  28. function pdate {
  29. DATE=$(date +%y-%m-%d_%H:%M:%S)
  30. echo "[$DATE]"
  31. }
  32. function logecho {
  33. # Echo string and copy it to log while attaching the current date
  34. echo "$(pdate) $@"
  35. echo "$(pdate) $@" >> "$LOG"
  36. }
  37. while read line; do
  38. # if line is a comment, go to next line
  39. if $(echo "$line" | grep -qE "^\s*#"); then continue; fi
  40. RHOST=$(echo "$line" | cut -d";" -f1 | trim)
  41. RUSER=$(echo "$RHOST" | cut -d"@" -f1)
  42. ALLRDIR=$(echo "$line" | cut -d";" -f2 | trim)
  43. logecho "${RHOST}: Starting backups"
  44. if ! "${CURDIR}"/ssh-checker.sh "${RHOST}"; then
  45. logecho "${RHOST}: ERROR when connecting via SSH. Please run ssh-checker.sh to debug."
  46. logecho "${RHOST}: Aborting backup after an error."
  47. continue
  48. fi
  49. NORDIR=$(echo $ALLRDIR | grep -o "|" | wc -l)
  50. NORDIR=$[$NORDIR + 1]
  51. for ((i = 1; i <= $NORDIR; i++)); do
  52. RDIR=$(echo "$ALLRDIR" | cut -d"|" -f${i} | trim)
  53. if [ "${RDIR}" == "%virtual" ]; then
  54. RDIR=/var/www/virtual/${RUSER}
  55. DEST="$BACKUPDIR/$RHOST/$DATE/virtual"
  56. elif [ "${RDIR}" == "%mysql" ]; then
  57. RDIR=mysql
  58. DEST="$BACKUPDIR/$RHOST/$DATE/$(basename "${RDIR}")"
  59. elif [ "${RDIR}" == "%mails" ]; then
  60. RDIR=/home/${RUSER}/users
  61. DEST="$BACKUPDIR/$RHOST/$DATE/mails"
  62. elif [ "${RDIR}" == "%home" ]; then
  63. RDIR=/home/${RUSER}
  64. DEST="$BACKUPDIR/$RHOST/$DATE/home"
  65. else
  66. DEST="$BACKUPDIR/$RHOST/$DATE/$(basename "${RDIR}")"
  67. fi
  68. # Set Source directory, and make exception for %mysql
  69. SOURCE="${RDIR}"
  70. if [ "${RDIR}" == "mysql" ]; then SOURCE=/mysqlbackup/latest/${RUSER}; fi
  71. # Create backup destination if necessary
  72. if [ ! -e "${DEST}" ]; then mkdir -p "${DEST}"; fi
  73. # RSYNC
  74. logecho "${RHOST}: Downloading ${SOURCE} to ${DEST}"
  75. rsync -a -e "ssh -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o Compression=no -T -x ${SSH_KEY_ARG}" ${RHOST}:${SOURCE}/ "${DEST}"/
  76. # Pack backup directory, and delete uncompressed one
  77. logecho "${RHOST}: Archiving $(basename ${DEST})"
  78. tar cf ${DEST}.tar -C $(echo ${DEST} | sed "s|$(basename ${DEST})$||") $(basename ${DEST}) # TODO: avoid absolute paths
  79. rm -rf ${DEST}
  80. # Encrypt archive with GPG (it compresses at the same time)
  81. logecho "${RHOST}: Encrypting and compressing $(basename ${DEST})"
  82. gpg --output ${DEST}.tar.gpg --encrypt --recipient ${GPG} ${DEST}.tar
  83. rm ${DEST}.tar
  84. # Delete all old directories except the $MAXBAK most recent
  85. if [ $(ls -tp "${BACKUPDIR}"/"${RHOST}"/ | grep '/$' | wc -l | tr -d ' ') -gt $MAXBAK ]; then
  86. logecho "${RHOST}: Removing older backups of $(basename ${DEST})"
  87. ls -tpd "${BACKUPDIR}"/"${RHOST}"/* | grep '/$' | tail -n +$[$MAXBAK + 1] | xargs -0 | xargs rm -r --
  88. fi
  89. done
  90. done < "$HOSTS"
  91. logecho "Finished all operations."