├── README.md ├── backup.sh └── backup_runner.sh /README.md: -------------------------------------------------------------------------------- 1 | # VPS-Daily-Backup-Script 2 | Bash scripts for backing up your data automatically. 3 | -------------------------------------------------------------------------------- /backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Automatic Backup Script by Paddy Xu, 22/07/2014 4 | # 5 | # *) OVERVIEW 6 | # 7 | # This script is designed to perform backup operation of web-files, databases 8 | # and important configuration files on a daily basis. A full backup will be performed 9 | # once a month, while incremental backups is performed on the rest days of the month. 10 | # This script should be run by Cron service, and if necessary, manually. 11 | # 12 | # *) REQUIREMENTS 13 | # 14 | # *) 7-zip full package 15 | # *) Well-configured sendmail service 16 | # 17 | # *) LOGIC 18 | # 19 | # While preforming a full backup, the script will do the following task: 20 | # *) Close BBS 21 | # *) Backup databases 22 | # *) Backup all files 23 | # *) Reopen BBS 24 | # *) Remove full and incremental backup files of last month 25 | # 26 | # If now an incremental backup task is running, the following steps will be performed: 27 | # *) Close BBS 28 | # *) Backup binary log of databases, based on the latest full backup 29 | # *) Do incremental backup for files, based on the latest full backup 30 | # *) Reopen BBS 31 | # 32 | # Noticeably, the incremental backup is always based on the latest full backup, which 33 | # means that an existing incremental backup can be replaced by a latter incremental backup, 34 | # if they are both performed in the same month. 35 | # 36 | # The relation between full and incremental backup can be described as the following graph: 37 | # 38 | # +-------------------------------+-------------------------------+ 39 | # | Jan | Feb | 40 | # +-------------------------------+-------------------------------+ 41 | # ^ Full 1 42 | # ^------^ Incremental 1.1 43 | # ^--------------^ Incremental 1.2 44 | # ^----------------------^ Incremental 1.3 45 | # +-------------------------------+-------------------------------+ 46 | # ^ Full 2 47 | # ^------^ Incremental 2.1 48 | # ^--------------^ Incremental 2.2 49 | # ^----------------------^ Incremental 2.3 50 | # +-------------------------------+-------------------------------+ 51 | # ^ Full 3 52 | # 53 | 54 | SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd) 55 | 56 | ENCRYPT_KEY='GkU0Jx3^l004' 57 | 58 | # server configurations 59 | SQL_USER='root' 60 | SQL_PASS='MmW7830@Vb8&' 61 | DATABASE_NAME=("database1" "database2" "database3" "database4") 62 | FILE_DIR_NAME=("git" "web" "nginx" "php" "etc" ) 63 | FILE_DIR=( "/home/git" "/home/wwwroot" "/usr/local/nginx/conf" "/usr/local/php/etc" "/etc") 64 | FILE_DIR_LENGTH=${#FILE_DIR_NAME[@]} 65 | CK_LOCK_FILE=/home/wwwroot/example.com/maintain.lock 66 | SQL_LOG_DIR=/usr/local/mariadb/var 67 | BACKUP_DIR=$SCRIPT_DIR/data 68 | FULL_BACKUP_BASE_DIR=$BACKUP_DIR/full 69 | INCR_BACKUP_BASE_DIR=$BACKUP_DIR/incremental 70 | 71 | CURRENT_MONTH=$(date +%Y-%m) 72 | CURRENT_DAY=$(date +%Y-%m-%d) 73 | LAST_MONTH=$(date -d last-month +%Y-%m) 74 | YESTERDAY=$(date -d yesterday +%Y-%m-%d) 75 | 76 | FULL_BACKUP_DIR=$FULL_BACKUP_BASE_DIR/$CURRENT_MONTH #/home/backup/full/2014-01 77 | INCR_BACKUP_MONTH_DIR=$INCR_BACKUP_BASE_DIR/$CURRENT_MONTH #/home/backup/incremental/2014-01 78 | INCR_BACKUP_DIR=$INCR_BACKUP_BASE_DIR/$CURRENT_MONTH/$CURRENT_DAY #/home/backup/incremental/2014-01/2014-01-03 79 | LAST_FULL_BACKUP_DIR=$FULL_BACKUP_BASE_DIR/$LAST_MONTH #/home/backup/full/2013-12 80 | LAST_INCR_BACKUP_DIR=$INCR_BACKUP_BASE_DIR/$LAST_MONTH #/home/backup/incremental/2013-12 81 | 82 | function shutdown_bbs { 83 | echo "Shutting down BBS..." 84 | touch $CK_LOCK_FILE 85 | sleep 5 # wait some time... 86 | } 87 | 88 | function reopen_bbs { 89 | echo "Reopening BBS..." 90 | sleep 5 # wait some time... 91 | rm -f $CK_LOCK_FILE 92 | } 93 | 94 | function func_full_backup { 95 | echo "Performing full backup..." 96 | 97 | # 98 | # Delete existing backup files 99 | # 100 | rm -rf $FULL_BACKUP_DIR/* 101 | rm -rf $INCR_BACKUP_MONTH_DIR/* 102 | 103 | rm -rf $LAST_FULL_BACKUP_DIR 104 | rm -rf $LAST_INCR_BACKUP_DIR 105 | 106 | # 107 | # Databases 108 | # 109 | echo "Deleting all database binary log files..." 110 | /usr/local/mariadb/bin/mysql -u$SQL_USER -p$SQL_PASS -e 'RESET MASTER' 111 | 112 | for db in "${DATABASE_NAME[@]}" 113 | do 114 | echo "Dumping ${db}..." 115 | /usr/local/mariadb/bin/mysqldump -u$SQL_USER -p$SQL_PASS --extended-insert=FALSE ${db} > $FULL_BACKUP_DIR/${db}.sql 116 | done 117 | 118 | echo "Rolling up databases..." 119 | 7z a -mmt -mhe -mx3 -m0=PPMd -p$ENCRYPT_KEY $FULL_BACKUP_DIR/databases.7z $FULL_BACKUP_DIR/*.sql 120 | rm -f $FULL_BACKUP_DIR/*.sql 121 | 122 | echo "Database backup finished" 123 | 124 | # 125 | # Files 126 | # 127 | echo "Rolling up files..." 128 | for (( i=0; i<${FILE_DIR_LENGTH}; i++ )) 129 | do 130 | echo "${FILE_DIR_NAME[$i]}: ${FILE_DIR[$i]}:" 131 | 7z a -r -mmt -mhe -mx3 -m0=PPMd -p$ENCRYPT_KEY $FULL_BACKUP_DIR/files_${FILE_DIR_NAME[$i]}.7z ${FILE_DIR[$i]}/* 132 | done 133 | 134 | echo "Files backup finished" 135 | } 136 | 137 | function func_incremental_backup { 138 | echo "Performing incremental backup based on full backup on $CURRENT_MONTH..." 139 | 140 | # 141 | # Binary logs 142 | # 143 | echo "Flushing binary log files..." 144 | /usr/local/mariadb/bin/mysql -u$SQL_USER -p$SQL_PASS -e 'FLUSH LOGS' 145 | echo "Copying binary logs..." 146 | temp=(`/usr/local/mariadb/bin/mysql -u$SQL_USER -p$SQL_PASS -B -N -e 'SHOW MASTER STATUS' | xargs`) 147 | current_log=./${temp[0]} 148 | all_logs=(`cat $SQL_LOG_DIR/mysql-bin.index | xargs`) 149 | 150 | for log in "${all_logs[@]}" 151 | do 152 | if [ "$log" == "$current_log" ] #Do not copy the log now is using 153 | then 154 | continue 155 | fi 156 | 157 | echo "Copying binary log $log" 158 | cp $SQL_LOG_DIR/$log $INCR_BACKUP_DIR/$log 159 | done 160 | 161 | echo "Rolling up binary logs..." 162 | 7z a -mmt -mhe -mx3 -m0=PPMd -p$ENCRYPT_KEY $INCR_BACKUP_DIR/databases_inc.7z $INCR_BACKUP_DIR/mysql-bin.* 163 | rm -f $INCR_BACKUP_DIR/mysql-bin.* 164 | 165 | echo "Database backup finished" 166 | 167 | # 168 | # Files 169 | # 170 | echo "Rolling up files incrementally..." 171 | for (( i=0; i<${FILE_DIR_LENGTH}; i++ )) 172 | do 173 | echo "${FILE_DIR_NAME[$i]}: ${FILE_DIR[$i]}:" 174 | 7z u $FULL_BACKUP_DIR/files_${FILE_DIR_NAME[$i]}.7z -r -mmt -mhe -mx3 -m0=PPMd -p$ENCRYPT_KEY -u- -up0q3r2x2y2z0w2\!$INCR_BACKUP_DIR/files_${FILE_DIR_NAME[$i]}_inc.7z ${FILE_DIR[$i]}/* 175 | done 176 | 177 | echo "Files backup finished" 178 | } 179 | 180 | echo "Starting, time is now $(date)" 181 | 182 | mkdir -p $FULL_BACKUP_DIR 183 | mkdir -p $INCR_BACKUP_DIR 184 | 185 | shutdown_bbs 186 | 187 | # If today is the 1st or 15th day of this month, do full backup. Otherwise, do incremental backup. 188 | if [ `date +%d` == 01 ] || [ `date +%d` == 15 ] 189 | then 190 | func_full_backup 191 | else 192 | func_incremental_backup 193 | fi 194 | 195 | reopen_bbs 196 | echo "Finished, time is now $(date)" 197 | -------------------------------------------------------------------------------- /backup_runner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will redirect the output data into file, and try to determine whether there exists any error. 4 | # If it does, emails will be send to administrators. 5 | 6 | ADMIN_MAIL=("yourname1@example.com" "yourname2@example.com") 7 | SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd) 8 | 9 | /bin/bash $SCRIPT_DIR/backup.sh > $SCRIPT_DIR/backup.log 10 | 11 | if cat $SCRIPT_DIR/backup.log | grep -iq "error:" 12 | then 13 | # Send notification to administrators 14 | for m in "${ADMIN_MAIL[@]}" 15 | do 16 | mail -s "$(date +%Y-%m-%d): Backup error occurred" $m < $SCRIPT_DIR/backup.log 17 | done 18 | else 19 | echo "Everything is okay." 20 | fi 21 | --------------------------------------------------------------------------------