#!/bin/bash #/###################################################################\ #| Make backup of castanedo.es server compressed with: | #| -Gzip | #| -Bzip2 | #| -XZ | #| -7zip | #| and encrypt it. | #| | #| Guzmán Castanedo (guzman@castanedo.es) | #| Version 1.9 (March 2018) | #| Licence: GPL v3.0 -> https://www.gnu.org/licenses/gpl-3.0.en.html | #\###################################################################/ function usage { printf "%s Version 1.9\n" $(basename $0) printf "Usage: %s [options]... -z|-j|-J \n" $(basename $0) printf "Make a encrypted backup of a server compressed with: \n" printf "\t·Gzip (tar.gz or tar.gz.gpg)\n" printf "\t·Bzip2 (tar.bz2 or tar.gz.gpg)\n" printf "\t·XZ (tar.xz or tar.xz.gpg)\n" printf "\t·7Z (7z)\n" printf "\n" printf "Backup Options:\n" printf "\t-d, --directory dir: backup directory\n" printf "\t\tDefault: %s\n" $backupDir printf "\t-p, --prefix name: prefix for the name of the backup\n" printf "\t\tDefault: %s\n" $backupPrefix printf "\t--no-postfix: disable the postfi: the full name will be the prefix\n" printf "\t\tDefault: prefix-yyyy-mm-dd(date)-XXXXXX(random)\n" printf "\t--no-remove: no remove old files\n" printf "\t\tDefault: false\n" printf "\t--remove-days numbet: set number of days to considere a backup old\n" printf "\t\tDefault: %s\n" $deleteDays printf "\t-u, --user uid: name of the user owner of the backup\n" printf "\t\tDefault: %s\n" $user printf "\t-g, --group gid: name of the group owner of the backup\n" printf "\t\tDefault: %s\n" $group printf "\t--permision-mask number: octal mask to set accesss permision of the backup\n" printf "\t\tDefault: %s\n" $permisionMask printf "\n" printf "Compression Options:\n" printf "\t-z, --gzip: compress using gzip (tar.gz or tar.gz.gpg)\n" printf "\t-j, --bzip2: compress using bzip2 (tar.bz2 or tar.bz2.gpg)\n" printf "\t-J, --xz: compress using xz (tar.xz or tar.xz.gpg)\n" printf "\t-7, --7zip: compress using 7z (7z)\n" printf "\n" printf "Encryption Options:\n" printf "\t-k, --key-id ID: set gpg2 public key-id used for encryption\n" printf "\t\tDefault: %s\n" $keyID printf "\t--no-encryption: disable the encryption of the backup\n" printf "\t\tDefault: %s\n" $noEncryption printf "\t--7z-password password: set password (ONLY for 7z)\n" printf "\t\tDefault: %s\n" $pass7z printf "\n" printf "Web Options:\n" printf "\t--web-dir dir: set web pages directory to backup\n" printf "\t\tDefault: %s\n" $webDir printf "\t--no-web: disable backup of web pages\n" printf "\t\tDefault: %s\n" $noWeb printf "\n" printf "SQL Options:\n" printf "\t--no-sql: disable MySQL/MAriaDB backup\n" printf "\t\tDefault: %s\n" $noSql printf "\n" printf "Nginx Options:\n" printf "\t--nginx-dir dir: set nginx configuration directory to backup\n" printf "\t\tDefault: %s\n" $nginxDir printf "\t--no-nginx: disable Nginx backup\n" printf "\t\tDefault: %s\n" $noNginx printf "\n" printf "Let's Encrypt Options:\n" printf "\t--letsencrypt-dir dir: set Let's Encrypt configuration directory to backup\n" printf "\t\tDefault: %s\n" $letsencryptDir printf "\t--no-letsencrypt: disable Let's Encrypt backup\n" printf "\t\tDefault: %s\n" $noLetsencrypt printf "\n" printf "Mail Options:\n" printf "\t--mail-dir dir: set Mailboxes directory to backup\n" printf "\t\tDefault: %s\n" $mailDir printf "\t\t--no-mail: disable mailboxes backup\n" printf "\t\tDefault: %s\n" $noMail printf "\n" printf "Home Options:\n" printf "\t--home-dir dir: set home directories to backup\n" printf "\t\tDefault: %s\n" $homeDir printf "\t--no-home: disable home directory backup\n" printf "\t\tDefault: %s\n" $noHome printf "\n" printf "GOGS Options:\n" printf "\t--gogs-dir dir: set GOGS Repository to backup\n" printf "\t\tDefault: %s\n" $gogsDir printf "\t--no-gogs: disable gogs backup\n" printf "\t\tDefault: %s\n" $noGogs exit } function makep7zip { #Destination file ext=".7z" backupOutput=$backupOutput$ext printf "Backup File (7z):\t%s\n" $backupOutput #Copy webpages code (except backup and main/public) if [ $noWeb = false ] && [ -d $webDir ];then printf "Compressing:\t%s\n" $webDir #cd /usr/share/nginx tempfile=$(mktemp -t exclude-XXX) echo "www/backup" > $tempfile echo "www/main/public" >> $tempfile 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput $webDir -x@$tempfile > /dev/null if [ $? != 0 ];then printf "WARNING:\tError copying web pages (Continue).\n" fi rm $tempfile fi #Copy MySQL databases (mysqldump) if [ $noSql = false ] && [ -x "$(which mysql)" ] && [ -x "$(which mysqldump)" ]; then list=$(mysql -u $mysqluser -p$mysqlpass -e "show DATABASES;") #Parse databases expect information_schema & performance_schema for database in $list; do valid=true for excep in Database information_schema performance_schema; do if [ $database = $excep ]; then valid=false break fi done if [ $valid = true ]; then printf "Compressing MySQL database:\t%s\n" $database.sql mysqldump -u $mysqluser -p$mysqlpass $database | 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput -simysql/$database.sql > /dev/null if [ $? != 0 ];then printf "WARNING:\tError compressing database (%s) (Continue).\n" $database fi fi done fi #Copy nginx configuration (sites-available) if [ $noNginx = false ] && [ -d $nginxDir ];then printf "Compressing:\t%s\n" $nginxDir 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput $nginxDir > /dev/null if [ $? != 0 ];then printf "WARNING:\tError copying nginx configuration (Continue)\n" fi fi #Copy Email (this could be heavy in the future) if [ $noMail = false ] && [ -d $mailDir ];then printf "Compressing:\t%s\n" $mailDir 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput $mailDir > /dev/null #tar -c -zf - $mailDir | 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput -simail.tar.gz > /dev/null if [ $? != 0 ];then printf "WARNING:\tError copying mailboxes (Continue)\n" fi fi #Copy Certificates (LetsEncrypt) if [ $noLetsencrypt = false ] && [ -d $letsencryptDir ];then printf "Compressing:\t%s\n" $letsencryptDir 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput $letsEncryptDir > /dev/null if [ $? != 0 ];then printf "WARNING:\tError copying Let's Encrypt certificates (Continue)\n" fi fi #Copy /home if [ $noHome = false ] && [ -d $homeDir ];then printf "Compressing:\t%s\n" $homeDir 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput $homeDir > /dev/null if [ $? != 0 ];then printf "WARNING:\tError copying home dir (Continue)\n" fi fi #Copy GOGS if [ $noGogs = false ] && [ -d $gogsDir ];then printf "Compressing:\t%s\n" $gogsDir 7z a -t7z -mx=9 -p$pass7z -mhe $backupOutput $gogsDir > /dev/null if [ $? != 0 ];then printf "WARNING:\tError copying GOGS Repository (Continue)\n" fi fi } function makeTar { #Destination file printf "Backup File:\t%s\n" $backupOutput.tar.gz.gpg #Copy webpages code (except backup and main/public) if [ $noWeb = false ] && [ -d $webDir ];then printf "Adding:\t%s\n" $webDir tar -rf $tempOutput -C $(dirname $webDir) --exclude=www/backup --exclude=www/main/public $(basename $webDir) > /dev/null 2>&1 if [ $? != 0 ]; then printf "WARNING:\tError copying web pages (Continue).\n" fi fi #Copy MySQL databases (mysqldump) if [ $noSql = false ] && [ -x "$(which mysql)" ] && [ -x "$(which mysqldump)" ]; then list=$(mysql -u $mysqluser -p$mysqlpass -e "show DATABASES;" 2> /dev/null) mkdir /tmp/mysql #Parse databases expect information_schema & performance_schema for database in $list; do valid=true for excep in Database information_schema performance_schema; do if [ $database = $excep ]; then valid=false break fi done if [ $valid = true ]; then printf "Adding MySQL database:\t%s\n" $database.sql mysqldump -u $mysqluser -p$mysqlpass $database > /tmp/mysql/$database.sql 2> /dev/null if [ $? != 0 ];then printf "WARNING:\tError extracting database (%s) (Continue).\n" $database continue fi tar -rf $tempOutput -C /tmp mysql/$database.sql > /dev/null 2>&1 if [ $? != 0 ];then printf "WARNING:\tError adding to tar (%s) (Continue)\n" fi rm /tmp/mysql/$database.sql fi done rmdir /tmp/mysql fi #Copy nginx configuration (sites-available) if [ $noNginx = false ] && [ -d $nginxDir ];then printf "Adding:\t%s\n" $nginxDir tar -rf $tempOutput -C $(dirname $nginxDir) $(basename $nginxDir) > /dev/null 2>&1 if [ $? != 0 ];then printf "WARNING:\tError copying nginx configuration (Continue)\n" fi fi #Copy Email (this could be heavy in the future) if [ $noMail = false ] && [ -d $mailDir ];then printf "Adding:\t%s\n" $mailDir tar -rf $tempOutput -C $(dirname $mailDir) $(basename $mailDir) > /dev/null 2>&1 if [ $? != 0 ];then printf "WARNING:\tError copying mailboxes (Continue)\n" fi fi #Copy Certificates (LetsEncrypt) if [ $noLetsencrypt = false ] && [ -d $letsencryptDir ];then printf "Adding:\t%s\n" $letsencryptDir tar -rf $tempOutput -C $(dirname $letsencryptDir) $(basename $letsencryptDir) > /dev/null 2>&1 if [ $? != 0 ];then printf "WARNING:\tError copying Let's Encrypt certificates (Continue)\n" fi fi #Copy /home if [ $noHome = false ] && [ -d $homeDir ];then printf "Adding:\t%s\n" $homeDir tar -rf $tempOutput -C $(dirname $homeDir) $(basename $homeDir) > /dev/null 2>&1 if [ $? != 0 ];then printf "WARNING:\tError copying home dir (Continue)\n" fi fi #Copy GOGS if [ $noGogs = false ] && [ -d $gogsDir ];then printf "Adding:\t/opt/gogs\n" tar -rf $tempOutput -C $(dirname $gogsDir) $(basename $gogsDir) > /dev/null 2>&1 if [ $? != 0 ];then printf "WARNING:\tError copying GOGS Repository (Continue)\n" fi fi } function gzUnencrypted { ext=".tar.gz" backupOutput=$backupOutput$ext printf "Compressing (GZIP)... %s\n" $backupOutput gzip -9 --stdout $tempOutput > $backupOutput if [ $? != 0 ]; then printf "ERROR:\tImpossible to compress (%s)\n" $backupOutput$ext exit 1 fi rm $tempOutput } function gzEncrypted { ext=".tar.gz.gpg" backupOutput=$backupOutput$ext printf "Compressing (GZIP) and encrypting... %s\n" $backupOutput gzip -9 --stdout $tempOutput | gpg2 --no-batch --output $backupOutput --encrypt -r $keyID - if [ $? != 0 ]; then printf "ERROR:\tImpossible to compress (%s)\n" $backupOutput$ext exit 1 fi rm $tempOutput } function bz2Unencrypted { ext=".tar.bz2" backupOutput=$backupOutput$ext printf "Compressing (BZIP2)... %s\n" $backupOutput bzip2 -9 --stdout $tempOutput > $backupOutput if [ $? != 0 ]; then printf "ERROR:\tImpossible to compress (%s)\n" $backupOutput$ext exit 1 fi rm $tempOutput } function bz2Encrypted { ext=".tar.bz2.gpg" backupOutput=$backupOutput$ext printf "Compressing (BZIP2) and encrypting... %s\n" $backupOutput bzip2 -9 --stdout $tempOutput | gpg2 --no-batch --output $backupOutput --encrypt -r $keyID - if [ $? != 0 ]; then printf "ERROR:\tImpossible to compress (%s)\n" $backupOutput$ext exit 1 fi rm $tempOutput } function xzUnencrypted { ext=".tar.xz" backupOutput=$backupOutput$ext printf "Compressing (XZ)... %s\n" $backupOutput xz -9 --stdout $tempOutput > $backupOutput if [ $? != 0 ]; then printf "ERROR:\tImpossible to compress (%s)\n" $backupOutput$ext exit 1 fi rm $tempOutput } function xzEncrypted { ext=".tar.xz.gpg" backupOutput=$backupOutput$ext printf "Compressing (XZ) and encrypting... %s\n" $backupOutput xz -9 --stdout $tempOutput | gpg2 --no-batch --output $backupOutput --encrypt -r $keyID - if [ $? != 0 ]; then printf "ERROR:\tImpossible to compress (%s)\n" $backupOutput$ext exit 1 fi rm $tempOutput } #Check root startTime=$(date +"%s") if [ $(id -u) -ne 0 ]; then printf "ERROR:\tNeed to be root :O\n" exit 1 fi #Data mysqluser="root" mysqlpass="mysqlpasswd" keyID="A288A3FB" pass7z="password-for-7z" backupDir=/var/www/backup backupPrefix="backup-castanedo.es" backupName=$backupPrefix-$(date +"%Y-%m-%d")-$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 6 | head -n 1) backupOutput=$backupDir/$backupName tempOutput=/tmp/$backupName.tar deleteDays="15" user="www-data" group="www-data" #Routes webDir="/var/www" nginxDir="/etc/nginx" mailDir="/var/mail" letsencryptDir="/etc/letsencrypt" homeDir="/home" gogsDir="/opt/gogs" #Control noEncryption=false gzipOn=false bzip2On=false xzOn=true p7zipOn=false permisionMask=640 removeOld=true noWeb=false noSql=false noNginx=false noMail=false noLetsencrypt=false noHome=false noGogs=false #Parse args #TEMP="$(getopt)" #usage #make tar file or 7z if [ $p7zipOn = true ];then if [ ! -x $(which 7z) ];then printf "ERROR:\tp7zip Not Installed\n" exit 1 fi makep7zip else if [ ! -x $(which tar) ];then printf "ERROR:\tTAR Not Installed\n" exit 1 fi makeTar fi #Compression and encryption if [ $gzipOn = true ];then if [ ! -x $(which gzip) ];then printf "ERROR:\tGzip Not Installed\n" rm $tempOutput exit 1 fi if [ $noEncryption = true ] || [ ! -x $(which gpg2) ];then gzUnencrypted else gzEncrypted fi elif [ $bzip2On = true ];then if [ ! -x $(which bzip2) ];then printf "ERROR:\tBzip2 Not Installed\n" rm $tempOutput exit 1 fi if [ $noEncryption = true ] || [ ! -x $(which gpg2) ];then bz2Unencrypted else bz2Encrypted fi elif [ $xzOn = true ];then if [ ! -x $(which xz) ];then printf "ERROR:\tXZ Not Installed\n" rm $tempOutput exit 1 fi if [ $noEncryption = true ] || [ ! -x $(which gpg2) ];then xzUnencrypted else xzEncrypted fi elif [ $p7zipOn = true ];then #Nothing to do printf "moo" > /dev/null else printf "ERROR:\tCompression method not set\n" rm $tempOutput exit 1 fi #Permissions chown $user:$group $backupOutput chmod $permisionMask $backupOutput #Remove files older than 15 days if [ $removeOld = true ];then printf "Eliminando backups antiguos (+15 dias)\n" find $backupDir -mindepth 1 -mtime +$deleteDays -type f -iname $backupPrefix*$ext -delete if [ $? != 0 ];then printf "WARNING:\tError eliminando backup's antiguos (%s dias)\n" $deleteDays fi fi #End finalTime=$(date +"%s") echo "------------------------------------------------" printf "Backup completado con exito en %s segundos :)\n" $((finalTime-startTime)) echo "------------------------------------------------"