#!/bin/bash

## Remote Server Backup Script
## Author: Ze'ev Schurmann
## Reddit: u/thisiszeev
## License: GPL-3.0 or later

## This script can only backup one server. So you need a seperate folder for each server. Put this file in each folder and apply
## the relative settings to each server. If you want to get Telegram notifications then check the API documents on the Telegram
## Website. Use a cron job to schedule each run. If you have more than one server, then stagger them. If you are backing up to a
## local machine that is not on redundant power, schedule each backup to run more than once a day, just incase of a power failure
## during a backup. The script will know if the last attempt was successful or not.

## Dependancies:
## rsync, ssh, tar, gzip, wget
## make sure you have key pair authentication setup for ssh. Rsync must be installed on both the remote server and the local machine.

## Use the SQLDumps script to export all MySQL and MariaDB databases on the server. Ensure the SQLDump runs long before this script
## runs to ensure that all databases are completely dumped.

## Example crontab entries (exclude the ##)

## 30 2    * * *   root    cd /media/backupdrive/server1 && bash backup.sh
## 30 5    * * *   root    cd /media/backupdrive/server2 && bash backup.sh
## 30 8    * * *   root    cd /media/backupdrive/server1 && bash backup.sh
## 05 11   * * *   root    cd /media/backupdrive/server2 && bash backup.sh
## 30 14   * * *   root    cd /media/backupdrive/server1 && bash backup.sh
## 30 17   * * *   root    cd /media/backupdrive/server2 && bash backup.sh
## 30 20   * * *   root    cd /media/backupdrive/server1 && bash backup.sh
## 30 23   * * *   root    cd /media/backupdrive/server2 && bash backup.sh

## Please consider making me small donation. Even though my scripts are open source and free to use, I still need to eat. And the
## occasional bottle of wine also goes down well.
## $5 buys me a cup of coffee
## $10 buys me a nice burger
## $20 buys me a bottle of wine
## Anything above that will be awesome as well.
## You can send me a donation via Paypal https://www.paypal.com/paypalme/thisiszeev
## Drop me a message on Reddit if you do make a donation.
## Support is only offered freely to those who donate $20 or more.
## Your donation contributes to further development.
## If you need a custom script, contact me on Reddit for pricing.



## Telegram API and Channel Settings

## Set usetelegram to true to get sent Telegram notifications. The Telegram API documentation covers how to obtain a bot key and how
## to assign the bot to a channel. Channels are used as it means notifications can be sent to more than one person if they are all
## in the same channel.

usetelegram=false
tgapi="placekeyhere"
tgch="placechannelhere"


## Backup Settings

## patharray contains a list of the folders you need to backup.
patharray=("/var/log" "/var/www" "/var/sqldumps" "/var/mail" "/var/vmail")

## serverlogin is your SSH login
serverlogin="root@server1.example.com"
servername="Server1"

## keepday is the day of the week you want for you weekly backups.
keepday="sunday"


function ShiftMonths {
  echo "Shifting months and copying $dayname.tar.gz to month1.tar.gz" >> backup.log
  rm month6.tar.gz
  mv month5.tar.gz month6.tar.gz
  mv month4.tar.gz month5.tar.gz
  mv month3.tar.gz month4.tar.gz
  mv month2.tar.gz month3.tar.gz
  mv month1.tar.gz month2.tar.gz
  cp $dayname.tar.gz month1.tar.gz
}

function ShiftWeeks {
  echo "Shifting weeks and copying sunday.tar.gz to week1.tar.gz" >> backup.log
  rm week5.tar.gz
  mv week4.tar.gz week5.tar.gz
  mv week3.tar.gz week4.tar.gz
  mv week2.tar.gz week3.tar.gz
  mv week1.tar.gz week2.tar.gz
  mv sunday.tar.gz week1.tar.gz
  ln -s week1.tar.gz sunday.tar.gz
}

function PrepareFiles {
  if [ ! -f sunday.tar.gz ]; then
  	touch sunday.tar.gz
  	echo "Init Sun"
  fi

  if [ ! -f monday.tar.gz ]; then
  	touch monday.tar.gz
  	echo "Init Mon"
  fi

  if [ ! -f tuesday.tar.gz ]; then
  	touch tuesday.tar.gz
  	echo "Init Tue"
  fi

  if [ ! -f wednesday.tar.gz ]; then
  	touch wednesday.tar.gz
  	echo "Init Wed"
  fi

  if [ ! -f thursday.tar.gz ]; then
  	touch thursday.tar.gz
  	echo "Init Thu"
  fi

  if [ ! -f friday.tar.gz ]; then
  	touch friday.tar.gz
  	echo "Init Fri"
  fi

  if [ ! -f saturday.tar.gz ]; then
  	touch saturday.tar.gz
  	echo "Init Sat"
  fi

  if [ ! -f month1.tar.gz ]; then
  	touch month1.tar.gz
  	echo "Init M1"
  fi

  if [ ! -f month2.tar.gz ]; then
  	touch month2.tar.gz
  	echo "Init M2"
  fi

  if [ ! -f month3.tar.gz ]; then
  	touch month3.tar.gz
  	echo "Init M3"
  fi

  if [ ! -f month4.tar.gz ]; then
  	touch month4.tar.gz
  	echo "Init M4"
  fi

  if [ ! -f month5.tar.gz ]; then
  	touch month5.tar.gz
  	echo "Init M5"
  fi

  if [ ! -f month6.tar.gz ]; then
  	touch month6.tar.gz
  	echo "Init M6"
  fi

  if [ ! -f week1.tar.gz ]; then
  	touch week1.tar.gz
  	echo "Init W1"
  fi

  if [ ! -f week2.tar.gz ]; then
  	touch week2.tar.gz
  	echo "Init W2"
  fi

  if [ ! -f week3.tar.gz ]; then
  	touch week3.tar.gz
  	echo "Init W3"
  fi

  if [ ! -f week4.tar.gz ]; then
  	touch week4.tar.gz
  	echo "Init W4"
  fi

  if [ ! -f week5.tar.gz ]; then
  	touch week5.tar.gz
  	echo "Init W5"
  fi

  for ((n=0; n<${#patharray[@]}; n++))
  do
    mkdir -p "./backup${patharray[$n]}"
  done
}

dom=$( date +%d )

if [ -f backup.log ]; then
  check=$( tail -1 backup.log )
  if [[ -z $check ]]; then
    sleep 0.1s
  elif [[ $check == "T_$dom" ]]; then
    echo "Backup already completed successfully today!"
    exit
  fi
fi

firstruncheck=$( ls -1 | grep "tar.gz")

if [[ -z $firstruncheck ]]; then
  PrepareFiles
fi

SECONDS=0

if [[ $usetelegram == true ]]; then
  string="Starting backup of $servername."
  wget -qO- "https://api.telegram.org/bot$tgapi/sendMessage?chat_id=$tgch&text=$string" &> /dev/null
fi

dow=$( date +%u )

if [ $dow == "1" ]
then
  dayname="monday"
elif [ $dow == "2" ]
then
  dayname="tuesday"
elif [ $dow == "3" ]
then
  dayname="wednesday"
elif [ $dow == "4" ]
then
  dayname="thursday"
elif [ $dow == "5" ]
then
  dayname="friday"
elif [ $dow == "6" ]
then
  dayname="saturday"
else
  dayname="sunday"
fi

echo "Start: $( date )" >> backup.log

for ((n=0; n<${#patharray[@]}; n++)); do
  if [ -z $1 ]; then
    rsync -avhPz --delete "$serverlogin:${patharray[$n]}/" "./backup${patharray[$n]}/"
  elif [ $1 == "quiet" ]; then
    rsync -avhqz --delete "$serverlogin:${patharray[$n]}/" "./backup${patharray[$n]}/"
  else
    rsync -avhPz --delete "$serverlogin:${patharray[$n]}/" "./backup${patharray[$n]}/"
  fi
done

echo "Rsync complete: $( date )" >> backup.log
echo "Day of Week = $dow | Day of Month = $dom" >> backup.log
echo "Generating $dayname.tar.gz" >> backup.log

rm $dayname.tar.gz

if [ -z $1 ]; then
  tar -czvf $dayname.tar.gz ./backup
elif [ $1 == "quiet" ]; then
  tar -czf $dayname.tar.gz ./backup
else
  tar -czvf $dayname.tar.gz ./backup
fi

if [ $dom == "1" ]; then
  ShiftMonths
elif [ $dom == "01" ]; then
  ShiftMonths
fi

if [ $dayname == $keepday ]
then
  ShiftWeeks
fi

temp=( $( du -b ./backup/ | tail -1 ) )
size1=${temp[0]}
size2=$( stat -c%s $dayname.tar.gz )
size1si=$( numfmt --to=iec-i --suffix=B --format="%9.2f" $size1 )
size2si=$( numfmt --to=iec-i --suffix=B --format="%9.2f" $size2 )
size2percent=$(( size2 * 100 ))
ratio=$( expr $size2percent / $size1 )
duration=$SECONDS
echo "Finished: $( date )" >> backup.log
echo "Data size: $size1si | Archive size: $size2si | Ratio: $ratio%" >> backup.log
echo "T_$dom" >> backup.log
tail -n 5000 backup.log > temp.log
rm backup.log
mv temp.log backup.log

if [[ $usetelegram == true ]]; then
  echo "Backup of $servername Complete: $( date )" >> tg.txt
  echo "Data Size: $size1si" >> tg.txt
  echo "Archive Size: $size2si" >> tg.txt
  echo "Ratio: $ratio%" >> tg.txt
  echo "Duration: $( TZ=UTC0 printf '%(%H:%M:%S)T\n' $duration )" >> tg.txt
  string=$( cat tg.txt )
  wget -qO- "https://api.telegram.org/bot$tgapi/sendMessage?chat_id=$tgch&text=$string" &> /dev/null
  rm tg.txt
fi