SHARE
TWEET

backup.sh (rotating archives, encrypted)

ulfben Jan 9th, 2018 (edited) 91 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/bin/bash
  2. # backup.sh - a basic backup script with grandfather-father-son rotation:
  3. #  - The rotation will do a daily backup Sunday through Friday.
  4. #  - On Saturday a weekly backup is done giving you four weekly backups a month.
  5. #  - The monthly backup is done on the first of the month, rotating two monthly backups (odd/even)
  6. #
  7. # The script was inspired by the Ubuntu Server Guide https://help.ubuntu.com/lts/serverguide/backups.html
  8. #
  9. # backup.sh will archive using tar + gzip (multithreaded) and then encrypt using 7z (AES256, no compression)
  10. # This is MUCH faster than it is to let 7z compress-&-encrypt in a single step - even at x=0.
  11. # Plus 7z is unfit for backup duty on Linux (see the man-page) so the tarball stays. :)
  12. #
  13. # Add a cron job to run at 03:00 every day:
  14. #   $ crontab -e
  15. #   0 3 * * * bash /home/myuser/scripts/backup.sh > /var/log/backup.log 2>&1
  16. #
  17. # //Ulf Benjaminsson, 2018-01
  18. if [ $(id -u) != 0 ] ; then
  19.     echo "please run backup.sh as root" >&2
  20.     exit 1
  21. fi
  22.  
  23. HOSTNAME=$(hostname -s)
  24. TIMESTAMP_FORMAT='%Y-%m-%d %H:%M:%S'
  25. ARCHIVE_PWD='secret' #used for 7z encryption. Will show up in process lists.
  26. BACKUP_OWNER='myuser'
  27. BACKUP_GROUP='mygroup'
  28.  
  29. MYSQL_DUMP_USER='BACKUPUSER'
  30. MYSQL_DUMP_PWD="secret" #will NOT be printed in logs or process lists
  31. DB_DESTINATION='/home/myuser/mysqldump'
  32.  
  33. FOLDERS_TO_BACKUP='/home /etc /var/www /var/log /usr/local /usr/share/phpmyadmin /root /boot /opt'
  34. ARCHIVE_DESTINATION='/media/backup/rotatingbackup'
  35.  
  36. # log(): timestamped output
  37. # Bash version in numbers like XYYYZZZ, where X is major version, YYY is minor, ZZZ is subminor.
  38. printf -v BV '%d%03d%03d' ${BASH_VERSINFO[0]} ${BASH_VERSINFO[1]} ${BASH_VERSINFO[2]}
  39. if [[ ${BV} -gt 4002000 ]]; then
  40.     log() { # Fast (builtin) but sec is highest precision for most implementations    
  41.         printf "[%(${TIMESTAMP_FORMAT})T] %s\\n" '-1' "$*"
  42.     }
  43. else
  44.     log() { # Slower, but support nanoseconds and legacy bash versions    
  45.         echo "[$(date +"${TIMESTAMP_FORMAT}")] $*"
  46.     }
  47. fi
  48.  
  49. # which week of the month is it (1-4)?
  50. day_num=$(date +%-d)
  51. if (( day_num <= 7 )); then
  52.     week_file="${HOSTNAME}-week1"
  53. elif (( day_num <= 14 )); then
  54.     week_file="${HOSTNAME}-week2"
  55. elif (( day_num <= 21 )); then
  56.     week_file="${HOSTNAME}-week3"
  57. else # day_num < 32
  58.     week_file="${HOSTNAME}-week4"
  59. fi
  60.  
  61. # is the month odd or even?
  62. is_even_month=$(expr $(date +%m) % 2)
  63. if [ "$is_even_month" -eq 0 ]; then
  64.     month_file="${HOSTNAME}-month2"
  65. else
  66.     month_file="${HOSTNAME}-month1"
  67. fi
  68.  
  69. # create archive filename.
  70. day=$(date +%A)
  71. if [ "$day_num" == 1 ]; then
  72.     archive_name=$month_file
  73. elif [ "$day" != "Saturday" ]; then
  74.         archive_name="${HOSTNAME}-$day"
  75. else
  76.     archive_name=$week_file
  77. fi
  78.  
  79. #build the full paths before starting the real work
  80. database_file="${DB_DESTINATION}/${archive_name}.sql.7z"
  81. archive_file="${ARCHIVE_DESTINATION}/${archive_name}.tgz"
  82. encrypted_archive_file="${archive_file}.7z"
  83.  
  84. log "Starting backup.sh"
  85.  
  86. if [ ! -d "${DB_DESTINATION}" ]
  87. then
  88.     log "ERROR: ${DB_DESTINATION} does not exist. Skipping mysqldump."
  89. else
  90.     log "Dumping MySQL to ${database_file}"
  91.     rm -f "${database_file}" # delete any pre-existing archive manually, because 7za is a PITA.
  92.     export MYSQL_PWD=$MYSQL_DUMP_PWD #read https://unix.stackexchange.com/a/369568 for the security implications   
  93.     mysqldump -u ${MYSQL_DUMP_USER} --all-databases | 7za a -mhe=on -p"${ARCHIVE_PWD}" -mx=9 -si "${database_file}"
  94.     unset MYSQL_PWD
  95.     chown ${BACKUP_OWNER}:${BACKUP_GROUP} "${database_file}"   
  96. fi # mysqldump
  97.  
  98. if [ ! -d "${ARCHIVE_DESTINATION}" ]
  99. then
  100.     log "ERROR: ${ARCHIVE_DESTINATION} does not exist. Skipping backup ${archive_name}"
  101.     log "backup.sh finished with errors!"
  102. else
  103.     log "Backing up ${FOLDERS_TO_BACKUP} to ${archive_file}"
  104.     tar --use-compress-program=pigz -Pcf "${archive_file}" $FOLDERS_TO_BACKUP
  105.        
  106.     # delete any pre-existing encrypted archive manually, because 7za is a PITA.
  107.     rm -f "${encrypted_archive_file}"
  108.    
  109.     log "Encrypting ${archive_file} to ${encrypted_archive_file}"
  110.     7za a -mhe=on -p"${ARCHIVE_PWD}" -mx=0 "${encrypted_archive_file}" "${archive_file}"
  111.  
  112.     #make sure the 7z was created before deleting the tarball
  113.     if [ -e "${encrypted_archive_file}" ]
  114.     then   
  115.         log "Removing unencrypted ${archive_file}"
  116.         rm -f "${archive_file}"
  117.         chown ${BACKUP_OWNER}:${BACKUP_GROUP} "${encrypted_archive_file}"
  118.     else
  119.         chown ${BACKUP_OWNER}:${BACKUP_GROUP} "${archive_file}"
  120.         log "ERROR: 7z failed! Leaving unencrypted ${archive_file} on drive!"
  121.     fi
  122.    
  123.     log "backup.sh finished!"
  124.     #list files ${ARCHIVE_DESTINATION} to check file sizes.
  125.     ls -lh "${ARCHIVE_DESTINATION}/"
  126. fi # archive creation
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top