├── portable_backup_cron ├── incremental_backup_cron ├── LICENSE ├── portable_backup ├── incremental_backup ├── README.md └── hbackup.bash /portable_backup_cron: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /usr/bin/systemd-cat -t portable_backup -p info /usr/local/bin/portable_backup 3 | -------------------------------------------------------------------------------- /incremental_backup_cron: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /usr/bin/systemd-cat -t incremental_backup -p info /usr/local/bin/incremental_backup 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Spas Zdravkov Spasov (pa4080) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /portable_backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # @author Spas Z. Spasov 4 | # @copyright 2021 Spas Z. Spasov 5 | # @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License, version 3 (or later) 6 | 7 | # Set the user that should have easy access to the backup 8 | # Set the target backup directory 9 | USER_BACKUP="pa4080" 10 | BACKUP_DIR="/home/${USER_BACKUP}/SystemBackup" 11 | 12 | # Get some environment variables 13 | TODAY="$(date +%Y-%m-%d)" 14 | SYSTEM="$(hostname)" 15 | 16 | ## Delete backup files older than 2 weeks before create the new one. 17 | find "$BACKUP_DIR" -mtime +14 -type f -delete 18 | 19 | ## MySQL Section. The first line is if you are using `mysqldump`, the next line is for `automysqlbackup`. I'm using both. 20 | #mysqldump -u'root' -p'' --all-databases | gzip > "$BACKUP_DIR"/mysql-all-db.sql.gz 21 | 22 | # Edit '/etc/default/automysqlbackup' and apply 'LATEST=yes' 23 | #automysqlbackup 24 | 25 | ## Tar Section. Create a backup file, with the current date in its name. 26 | ## Add -h to convert the symbolic links into a regular files. 27 | ## Backup some system files, also the entire `/home` directory, etc. 28 | ## --exclude some directories, for example the the browser's cache, `.bash_history`, etc. 29 | tar zcvf "${BACKUP_DIR}/${SYSTEM}-on-google-backup-${TODAY}.tgz" \ 30 | /etc/hosts /etc/sudoers* /var/spool/cron/crontabs /etc/cron* \ 31 | /etc/ssh /etc/pam.d/sshd \ 32 | /etc/fstab \ 33 | /etc/apache2 \ 34 | /etc/modsecurity \ 35 | /usr/share/modsecurity-crs.3 \ 36 | /etc/logrotate.d/apache2-modsec \ 37 | /etc/letsencrypt \ 38 | /etc/postfix/main.cf \ 39 | /etc/postfix/sasl_passwd.db \ 40 | /usr/local/bin \ 41 | /root/.ssh \ 42 | /root/.bashrc \ 43 | /root/.profile \ 44 | /var/www* \ 45 | /home/"${USER_BACKUP}" \ 46 | --exclude="$BACKUP_DIR" \ 47 | --exclude="/home/${USER_BACKUP}/.cache" \ 48 | --exclude="/home/${USER_BACKUP}/.bash_history" \ 49 | --exclude="/home/${USER_BACKUP}/.sudo_as_admin_successful" \ 50 | --exclude="/home/${USER_BACKUP}/.config" \ 51 | --exclude="/home/${USER_BACKUP}/upload" \ 52 | --exclude="/home/${USER_BACKUP}/Downloads" 53 | 54 | 55 | #"$BACKUP_DIR/mysql-all-db.sql.gz" /var/lib/automysqlbackup/latest/*.sql.gz \ 56 | #/etc/phpmyadmin/apache.conf /etc/mysql/debian.cnf \ 57 | #/etc/apache2 /etc/letsencrypt /etc/php/7.0/apache2/php.ini \ 58 | #/var/www \ 59 | #--exclude=/home/spas/.composer --exclude=/home/spas/.npm 60 | 61 | ## MySQL Section - remove the DB backup files, if you want: 62 | #rm /var/lib/automysqlbackup/latest/*.sql.gz 63 | #rm "$BACKUP_DIR/mysql-all-db.sql.gz" 64 | 65 | #rm /var/www/html/the-location/* 66 | #7za a -tzip -p'' -mem=AES256 "/var/www/html/the-location/my-backup-$TODAY.tgz.7z" "/var/backup/my-backup-$TODAY.tgz" 67 | 68 | chown -R $USER_BACKUP:$USER_BACKUP "$BACKUP_DIR" 69 | 70 | -------------------------------------------------------------------------------- /incremental_backup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @author Spas Z. Spasov 4 | # @copyright 2021 Spas Z. Spasov 5 | # @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License, version 3 (or later) 6 | 7 | # Set the source backup directory 8 | src_dir=("/home/spas" "/home/guest" "/root/.bashrc" "/root/.ssh/") 9 | 10 | # Set the targer backup directory (note in my case Backup/ is a mountpint) 11 | tgt_dir="/home/spas/Backup" 12 | 13 | # Exclude files matching PATTERN (the first two lines belong to my personal exclude list) 14 | exclude=("Backup/") 15 | exclude+=("Downloads/" "mnt/" "tmp/" "spas/vmware/Windows 10 x64/" "guest/Music" "guest/Videos" "output.*") 16 | exclude+=("~PlayOnLinux*" "kdenlive/") 17 | exclude+=(".adobe/" ".apport-ignore.xml" ".bash_history" ".cache/" ".compiz/" ".config/" ".cups/") 18 | exclude+=(".dbus/" ".dmrc" ".gconf/" ".gimp-2.8/" ".gitkraken/" ".gksu.lock" ".gnome/" ".gnupg/" ".gtk-bookmarks" ".gtk-recordmydesktop") 19 | exclude+=(".ICEauthority" ".lesshst" ".local/" ".~lock.script.code*" ".macromedia/" ".mozilla/" ".nano/" ".nv/" ".nvidia-settings-rc") 20 | exclude+=(".pki/" "*.swp" ".sudo_as_admin_successful" ".thumbnails/" ".Trash-1000/") 21 | exclude+=(".ViberPC/" "ViberDownloads/" ".vmware/" ".vscode" ".wget-hsts" ".wine/" ".Xauthority" ".xsession-errors*") 22 | 23 | # Remove the backups older than 2 months 24 | age=$(date +%F --date='2 months ago') 25 | for i in "$tgt_dir"/* 26 | do 27 | if [[ -d $i ]] && [[ ${age//-} -ge $(echo "$i" | sed -r 's/^.*([0-9]{4})-([0-9]{2})-([0-9]{2})T.*$/\1\2\3/') ]] 2>/dev/null 28 | then 29 | rm -rf "$i" 30 | fi 31 | done 32 | 33 | # Generate a list of source directories from the array 34 | # 'eval' is essential to use a variable as command or option 35 | src_dir=$(printf -- '"%s" ' "${src_dir[@]}") 36 | 37 | # Generate a list with exclude options from the array 38 | # --exclude=PATTERN :Exclude files matching PATTERN 39 | exclude=$(printf -- "--exclude '%s' " "${exclude[@]}") 40 | 41 | # Create the backup directory if doesn't exist 42 | [[ ! -d $tgt_dir ]] && mkdir -p "$tgt_dir" 43 | 44 | # current backup directory, e.g. "2017-04-29T13:04:50"; 45 | now=$(date +%FT%H:%M:%S) 46 | 47 | # previous backup directory 48 | prev=$(ls "$tgt_dir" | grep -e '^....-..-..T..:..:..$' | tail -1); 49 | 50 | make_backup() { 51 | if [[ -z $prev ]]; then 52 | # initial backup 53 | eval rsync -av --delete ${exclude} ${src_dir} "$tgt_dir/$now/" 54 | else 55 | # incremental backup 56 | eval rsync -av --delete --link-dest="$tgt_dir/$prev/" ${exclude} ${src_dir} "$tgt_dir/$now/" 57 | fi 58 | }; make_backup > "${tgt_dir}/.backup.log" 2>&1 59 | 60 | # Create statistics 61 | echo -e "\n${now}\t$(du -hs "$tgt_dir/$now")\n" >> "${tgt_dir}/.backup.log" 62 | df -h "$tgt_dir" >> "${tgt_dir}/.backup.log" 63 | exit 0; 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Backup Solutions 2 | 3 | A bundle of scripts, that contain few simple solutions for backup, which I'm using within my Ubuntu installations. 4 | 5 | ## Incremental backup using Rsync 6 | 7 | - This solution perfectly fits to 'desktop' systems, when you want easy access to your backup files and their history. 8 | 9 | - It is [based on this nice answer][1], provided by [PerlDuck][2] on Ask Ubuntu SE, where are provided detailed explanations. 10 | 11 | - There are two files: 12 | 13 | - [**`incremental_backup`**][3] - this is the main (`bash`) script. I would place it in `/usr/local/bin` to be accessible as shell command system wide. 14 | 15 | - [`incremental_backup_cron`][4] - this a (`sh`) script desingned to be placed in `/etc/cron.{daily,hourly,weekly}/`. 16 | 17 | - Installation on fly (without using git): 18 | 19 | ````shell 20 | sudo wget -O /usr/local/bin/incremental_backup https://raw.githubusercontent.com/metalevel-tech/simple-backup-solutions/master/incremental_backup 21 | sudo chmod +x /usr/local/bin/incremental_backup 22 | 23 | sudo wget -O /etc/cron.daily/incremental_backup_cron https://raw.githubusercontent.com/metalevel-tech/simple-backup-solutions/master/incremental_backup_cron 24 | sudo chmod +x /etc/cron.daily/incremental_backup_cron 25 | ```` 26 | 27 | ## Portable backup using Tar and 7zip 28 | 29 | - This solution perfectly fits to 'server' systems, when you want small and portable backups. 30 | 31 | - It is [based on this answer of mine][5] on Ask Ubuntu SE, where are provided detailed explanations. 32 | 33 | - There are two files: 34 | 35 | - [**`portable_backup`**][6] - this is the main (`bash`) script. I would place it in `/usr/local/bin` to be accessible as shell command system wide. 36 | 37 | - [`portable_backup_cron`][7] - this a (`sh`) script desingned to be placed in `/etc/cron.{daily,hourly,weekly}/`. 38 | 39 | - Installation on fly (without using git): 40 | 41 | ````shell 42 | sudo wget -O /usr/local/bin/portable_backup https://raw.githubusercontent.com/metalevel-tech/simple-backup-solutions/master/portable_backup 43 | sudo chmod +x /usr/local/bin/portable_backup 44 | 45 | sudo wget -O /etc/cron.daily/portable_backup_cron https://raw.githubusercontent.com/metalevel-tech/simple-backup-solutions/master/portable_backup_cron 46 | sudo chmod +x /etc/cron.daily/portable_backup_cron 47 | ```` 48 | 49 | ## Notes 50 | 51 | - [How to rsync multiple source folders - on Unix & Linux](https://unix.stackexchange.com/a/368216/201297) 52 | - [Make "rm" move files to trash instead of completely removing them - on WEB UPD8](http://www.webupd8.org/2010/02/make-rm-move-files-to-trash-instead-of.html) 53 | - [Command to move a file to Trash via Terminal - on Ask Ubuntu](https://askubuntu.com/q/213533/566421) 54 | - [How to compare two dates in a shell - on Unix & Linux](https://unix.stackexchange.com/q/84381/201297) 55 | - [**Exhaustive list of backup solutions for Linux** - on GitHub](https://github.com/sstark/others) 56 | 57 | [1]: https://askubuntu.com/a/1029653/566421 58 | [2]: https://askubuntu.com/users/504066/perlduck 59 | [3]: https://github.com/metalevel-tech/simple-backup-solutions/blob/master/incremental_backup 60 | [4]: https://github.com/metalevel-tech/simple-backup-solutions/blob/master/incremental_backup_cron 61 | [5]: https://askubuntu.com/a/1010102/566421 62 | [6]: https://github.com/metalevel-tech/simple-backup-solutions/blob/master/portable_backup 63 | [7]: https://github.com/metalevel-tech/simple-backup-solutions/blob/master/portable_backup_cron 64 | -------------------------------------------------------------------------------- /hbackup.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Stolen from Host.bg 4 | # Location and name: /usr/local/sbin/hbackup 5 | # Triggered by `sudo crontab -e`: 17 4 * * * /usr/local/sbin/hbackup > /dev/null 2>&1 6 | 7 | ### mysql user and pass 8 | MPASS="Xg***********V0" 9 | MUSER="xw******Cb" 10 | ### backup directories 11 | SOURCES="/home /etc /var/www" 12 | 13 | BACKUP_DIR="/hostbg_bkps" 14 | todays=$(date +'%Y-%m-%d') 15 | commands="rsync mysql" 16 | counter=0 17 | error=0 18 | ######### Variables ################## 19 | 20 | #Verifying that which is available. 21 | if [ -x /usr/bin/which ]; then 22 | echo " Command \"which\" exists" 23 | else 24 | echo " Command \"which\" does not exist, pls install" 25 | exit 0 26 | fi 27 | 28 | #Check whether all necessary commands available. 29 | for command in $commands; do 30 | echo " Check for command \"$command\" exists: " 31 | if which $command >/dev/null ; then 32 | echo " YES" 33 | else 34 | echo " Command $command not exists, pls install \"$command\"" 35 | exit 0 36 | fi 37 | done 38 | 39 | #Check folder /hostbg_bkps exist 40 | if [ ! -d "$BACKUP_DIR" ]; then 41 | echo " Create folder $BACKUP_DIR" 42 | mkdir $BACKUP_DIR 43 | else 44 | echo " Folder $BACKUP_DIR exist" 45 | fi 46 | 47 | 48 | rsync_back (){ 49 | last=$(ls -r /hostbg_bkps/sys/| head -1) 50 | echo " rsync -va --link-dest=${BACKUP_DIR}/sys/${last} $SOURCES $BACKUP_DIR/${todays} " 51 | ionice -c 3 nice -n +19 rsync -aq --ignore-errors --link-dest=${BACKUP_DIR}/sys/${last} $SOURCES $BACKUP_DIR/sys/${todays} 52 | if [ "$?" = 0 ]; then 53 | echo " Sucseful execute rsync -va --link-dest=${BACKUP_DIR}/sys/${last} $SOURCES $BACKUP_DIR/${todays}" 54 | else 55 | echo " $counter attempt execute rsync -va --link-dest=${BACKUP_DIR}/sys/${last} $SOURCES $BACKUP_DIR/${todays} !!!" 56 | if [ $counter != 2 ]; then 57 | let counter++ 58 | rsync_back 59 | else 60 | echo " Failed execute rsync -va --link-dest=${BACKUP_DIR}/sys/${last} $SOURCES $BACKUP_DIR/${todays}, please contact a system administrator !!!" 61 | export counter=1 62 | error=1 63 | fi 64 | fi 65 | 66 | } 67 | 68 | mysql_back () { 69 | #Check folder /hostbg_bkps exist 70 | if [ ! -d "$BACKUP_DIR/DBS/$todays" ]; then 71 | echo " Create folder $BACKUP_DIR/DBS/$todays" 72 | mkdir $BACKUP_DIR/DBS/$todays 73 | else 74 | echo " Folder $BACKUP_DIR/DBS/$todays exist" 75 | fi 76 | # check for work mysql 77 | # check_mysql_work=$(mysql -uhostbg -p6Vdu2XRGcwf1Zmph -e "select 1 + 1;") 78 | check_mysql_work=$(mysql -e "select 1 + 1;") 79 | if [ "$?" = 0 ]; then 80 | echo 81 | echo " Dump MySQL DB" 82 | # list_dbs=$(mysql -uhostbg -p6Vdu2XRGcwf1Zmph -N -B -e "SHOW DATABASES;") 83 | list_dbs=$(mysql -N -B -e "SHOW DATABASES;") 84 | for dump_dbs in $list_dbs; do 85 | func_dump_dps () { 86 | # mysqldump -uhostbg -p6Vdu2XRGcwf1Zmph -f --skip-lock-tables $dump_dbs | gzip > $BACKUP_DIR/DBS/$todays/${dump_dbs}-${todays}.sql.gz 87 | mysqldump -f --skip-lock-tables $dump_dbs | gzip > $BACKUP_DIR/DBS/$todays/${dump_dbs}-${todays}.sql.gz 88 | if [ "$?" = 0 ]; then 89 | echo " Successful dump $dump_dbs" 90 | else 91 | echo " $counter attempt dump $dump_dbs !!!" 92 | if [ $counter != 2 ]; then 93 | let counter++ 94 | func_dump_dps 95 | else 96 | echo " Failed dump $dump_dbs, please contact a system administrator !!!" 97 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set error_message='Some Data Base is not the dump';" 98 | export counter=0 99 | fi 100 | fi 101 | } 102 | func_dump_dps 103 | done 104 | else 105 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set error_message='Database server problem';" 106 | error=1 107 | fi 108 | } 109 | 110 | delete_old_back () { 111 | # Delete backup $BACKUP_DIR/sys/ 112 | folder_for_delete=$(ls -r $BACKUP_DIR/sys/ | tail -n +8) 113 | if [ -n "$folder_for_delete" ]; then 114 | for folder in $folder_for_delete; do 115 | echo " Delete folder $BACKUP_DIR/sys/${folder}" 116 | rm -rf $BACKUP_DIR/sys/${folder} 117 | done 118 | fi 119 | # Delete backup $BACKUP_DIR/DBS/ 120 | 121 | folder_for_delete=$(ls -r $BACKUP_DIR/DBS/ | tail -n +8) 122 | if [ -n "$folder_for_delete" ]; then 123 | for folder in $folder_for_delete; do 124 | echo " Delete folder $BACKUP_DIR/DBS/${folder}" 125 | rm -rf $BACKUP_DIR/DBS/${folder} 126 | done 127 | fi 128 | } 129 | 130 | successful_finish () { 131 | if [ "$error" == "0" ]; then 132 | # Successful finis backup and update check 133 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set error_message='No errors';" 134 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set last_backup='$todays';" 135 | delete_old_back 136 | # Remount backup disk Read-Only 137 | # mount -o remount,ro $get_backup_disk $BACKUP_DIR 138 | fi 139 | } 140 | 141 | backup_func () { 142 | export get_backup_disk="$get_backup_disk" 143 | mysql_back 144 | rsync_back 145 | successful_finish 146 | } 147 | 148 | # Check disk it's full 149 | for colone in `df /hostbg_bkps | tail -n 1`; do 150 | if [ `echo "$colone" | grep %` ]; then 151 | get_disk_usage=`echo "$colone" | cut -d"%" -f1` 152 | if [ $get_disk_usage -ge 90 ];then 153 | echo "No disk space in backup disk" 154 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set error_message='No disk space in backup disk';" 155 | exit 1 156 | fi 157 | fi 158 | done 159 | 160 | 161 | # Check disk it's exist and mounted 162 | exit_status_mount_hostbg_bkps=`grep $BACKUP_DIR /proc/mounts | grep -oE "ro|rw"` 163 | if [ -n "$exit_status_mount_hostbg_bkps" ];then 164 | get_backup_disk=`grep $BACKUP_DIR /proc/mounts | awk '{print $1}'` 165 | if [ -n "$get_backup_disk" ]; then 166 | if [ "$exit_status_mount_hostbg_bkps" = "ro" ];then 167 | mount -o remount,rw,noatime $get_backup_disk $BACKUP_DIR 168 | echo " Disk $get_backup_disk remount RW" 169 | backup_func 170 | else 171 | echo " Disk $get_backup_disk it's mount RW" 172 | backup_func 173 | fi 174 | else 175 | echo "No disk for backup mount" 176 | fi 177 | else 178 | backup_disk=$(ls /dev/ | grep ip) 179 | if [ -n "$backup_disk" ]; then 180 | echo " Mount disk $backup_disk in $BACKUP_DIR" 181 | mount -o noatime /dev/$backup_disk $BACKUP_DIR > /dev/null 2>&1 182 | backup_func 183 | else 184 | echo " No Disk for mount in ${BACKUP_DIR}" 185 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set error_message='No back disk for mount';" 186 | exit 1 187 | fi 188 | echo " Not success mount back disk" 189 | mysql -h 87.120.41.23 -u$MUSER -p$MPASS -D bk_monitoring -e "update perms set error_message='Not success mount back disk';" 190 | exit 1 191 | fi 192 | --------------------------------------------------------------------------------