Update – May 2013:
I’ve received a few emails asking how to prevent this script from continuously eating up disk space… Rather than re-invent the wheel, I just use built in Linux commands in my root crontab that run once a day:
0 4 * * * find /home/tim/backups/ -mtime +10 -exec rm {} \;
In this example I’m searching /home/tim/backups/ for files more than 10 days old and deleting them at 4am everyday.
Faced with an ever-so-common task of creating backup versions of my webfolders and mysql server, I set out last night to create a simple bash script to be triggered from either the commandline or cron scheduler.
What originally was just going to be a quick script with my usual commands, quickly evolved into well over 200 lines of bash script including options to run specific tasks as standalone jobs and easy configuration changes through simple variable assignments at the top of the file. You even have notifications via email with a ‘slim’ report or by sending the output to a text file.
I’ve tested this on multiple servers with no problems. If this helps you, please let me know!
Here’s a closer look at it: backup
#!/bin/bash
function header {
clear
echo "##########################################################################"
echo "# Tims Backup Script - August 2009 #"
echo "# (backup web folders and mysql databases to local and remote locations) #"
echo "##########################################################################"
echo
}
## Define Variables
# local folders and filenames
backupdir="/backups/" # include trailing slash!
basedir="/home/tim/www/tim/" # include trailing slash!
webfile="$(date +%Y%m%d)-webdirs.tgz"
# MySQL variables (create a backup account)
sqlfile="$(date +%Y%m%d)-sqldump.tgz"
sqlhost="localhost"
sqluser="backup"
sqlpass="password"
# SSH variables (assumes you have already paired ssh key with remote host)
scphost="192.168.4.105"
scpuser="tim"
scpremotepath="/home/$scpuser/backups/"
# Mail (requires /usr/bin/mail (mailutils package))
notify="[email protected]"
tmpmailfile="/tmp/notifymsg.txt" # use this if you want to send stdout as email
finalmsgfile="./backupemail.txt" # use this for slim emails
######################################################################
### USERS SHOULD NOT HAVE TO EDIT BELOW HERE! ###
######################################################################
# Define functions
function usage {
echo " Usage: $0 [OPTIONS] [confirm]"
echo
echo " STANDALONE OPTIONS:"
echo
echo " --listvars : List configured variables"
echo " --checkdirs : Check for required directories"
echo " --dumpmysql : Only dump MySQL"
echo " --dumpweb : Only dump web file"
echo " --scp : Only SCP existing files and exit"
echo " --rsync : Only rsync existing files and exit"
echo
echo " AUTOMATED OPTIONS:"
echo " [confirm] sends email to $notify on completion"
echo
echo " --local : Create & copy to $backupdir locally ($HOSTNAME)"
echo " --remote scp : Create & transfer files to $scphost using scp"
echo " --remote rsync: Create & transfer files to $scphost using rsync"
echo
exit
}
function checkdirs {
echo
echo "Checking for backupdir $backupdir :"
if [ -d $backupdir ]; then
echo " ...Backup directory found!"
echo
elif [ ! -d $backupdir ]
then
echo " ...Your backup directory does not exist!"
echo
echo "You can try manually creating it."
echo
echo "I am now crashing to your command prompt."
exit
fi
}
function web2local {
echo "Backing up web directory (may require sudo password):"
# create a tgz with permissions from basedir to backupdir
sudo tar cpPzf $backupdir$webfile $basedir
echo " ...finished creating web backup"
echo
}
function dumpmysql {
echo "Now performing MySQL dump on entire server."
# dump mysql data to tgz in backup directory
mysqldump -h $sqlhost --user="$sqluser" --password="$sqlpass" --all-databases | gzip > $backupdir$sqlfile
echo " ...finished MySQL dump"
echo
}
function scpfiles {
echo "Copying $backupdir$sqlfile to [email protected]$scphost:$scpremotepath$sqlfile"
scp $backupdir$sqlfile [email protected]$scphost:$scpremotepath$sqlfile
echo "Copying $backupdir$webfile to [email protected]$scphost:$scpremotepath$sqlfile"
scp $backupdir$webfile [email protected]$scphost:$scpremotepath$webfile
}
function rsyncfiles {
echo "Copying $backupdir$sqlfile to [email protected]$scphost:$scpremotepath$sqlfile"
rsync -av $backupdir$sqlfile [email protected]$scphost:$scpremotepath
echo "Copying $backupdir$webfile to [email protected]$scphost:$scpremotepath$sqlfile"
rsync -av $backupdir$webfile [email protected]$scphost:$scpremotepath
}
function tasktimer {
endtime="$(date +%s)"
elapsedtime="$(expr $endtime - $starttime)"
elapsedminutes=$(($elapsedtime/60))
elapsedseconds=$(($elapsedtime%60))
echo
if [ "$elapsedtime" -lt "60" ]; then
echo " Total elapsed time = $elapsedtime seconds"
else
echo "Total elapsed time = $elapsedminutes min $elapsedseconds secs"
fi
echo
}
function finalstats {
webfilesize="$(stat -c%s "$backupdir$webfile")"
webfilesizemb="$(expr $webfilesize / 1024 / 1024)"
sqlfilesize="$(stat -c%s "$backupdir$sqlfile")"
sqlfilesizemb="$(expr $sqlfilesize / 1024 / 1024)"
echo
echo "Final Results:"
echo " $backupdir$webfile = $webfilesize bytes ($webfilesizemb MB)"
echo " $backupdir$sqlfile = $sqlfilesize bytes ($sqlfilesizemb MB)"
if [ "$backuptype" != "Local" ]; then
echo
echo "Transferred to $webfile and $sqlfile to $scphost using $backuptype"
fi
tasktimer
}
function mailresults {
SUBJECT="Backup Results for $UID on $HOSTNAME"
TO="$notify"
finalstatsmsg=$(finalstats)
echo "$backuptype backup has been completed!" > $finalmsgfile
echo "$finalstatsmsg" >> $finalmsgfile
echo "Attempting to send mail to $notify"
# if [ "$3" == "slim" ]; then
/usr/bin/mail -s "$SUBJECT" -t "$TO" < $finalmsgfile
rm $finalmsgfile
# elif [ "$3" != "slim" ]; then
# /usr/bin/mail -s "$SUBJECT" -t "$TO" < $tmpmailfile
# rm $tmpmailfile
echo " ...sent!"
# fi
}
### The goods.
starttime="$(date +%s)"
header
if [ -z "$1" ]; then
usage
exit
elif [ "$1" == "--help" ]; then
usage
exit
elif [ "$1" == "--listvars" ]; then
echo "Defined Variables:"
echo
echo " Root Web Directory : $basedir"
echo " Backup Directory : $backupdir"
echo " Web Archive File : $backupdir$webfile"
echo " MySQL Archive File : $backupdir$sqlfile"
echo
echo " MySQL Host : $sqlhost"
echo " MySQL User : $sqluser"
echo " MySQL Pass : $sqlpass"
echo
echo " SCP / Rsync Host : $scphost"
echo " SCP / Rsync User : $scpuser"
echo " SCP / Rsync Remote Path : $scpremotepath"
echo
echo " Notification E-Mail : $notify"
echo
elif [ "$1" == "--checkdirs" ]; then
echo "** SINGLE TASK MODE **"
checkdirs
tasktimer
echo "** TASK COMPLETED **"
elif [ "$1" == "--dumpmysql" ]; then
echo "** SINGLE TASK MODE **"
dumpmysql
tasktimer
echo "** TASK COMPLETED **"
elif [ "$1" == "--dumpweb" ]; then
echo "** SINGLE TASK MODE **"
web2local
tasktimer
echo "** TASK COMPLETED **"
elif [ "$1" == "--scp" ]; then
echo "** SINGLE TASK MODE **"
scpfiles
tasktimer
echo "** TASK COMPLETED **"
elif [ "$1" == "--rsync" ]; then
echo "** SINGLE TASK MODE **"
rsyncfiles
tasktimer
echo "** TASK COMPLETED **"
elif [ "$1" == "--local" ]; then
backuptype="Local"
echo "** BEGINNING LOCAL BACKUP SEQUENCE **"
echo
checkdirs
web2local
dumpmysql
echo "** LOCAL BACKUP SEQUENCE COMPLETE **"
finalstats
if [ "$2" == "confirm" ]; then
mailresults
fi
elif [ "$1" == "--remote" ]; then
if [ -z "$2" ]; then
usage
exit
elif [ "$2" == "scp" ]; then
backuptype="Remote SCP"
echo "** BEGINNING REMOTE SCP BACKUP SEQUENCE **"
checkdirs
web2local
dumpmysql
scpfiles
echo
echo "** SCP BACKUP COMPLETED **"
echo
finalstats
if [ "$3" == "confirm" ]; then
mailresults
fi
echo
elif [ "$2" == "rsync" ]; then
backuptype="Remote RSYNC"
echo "** BEGINNING REMOTE RSYNC BACKUP SEQUENCE **"
checkdirs
web2local
dumpmysql
rsyncfiles
echo
echo "** RSYNC BACKUP COMPLETED **"
echo
finalstats
if [ "$3" == "confirm" ]; then
mailresults
fi
echo
else
usage
exit
fi
else
usage
exit
fi
echo
exit
Joshua Sigona
This is very useful. Worked like a charm on my server, thanks for that and great script!
Anonymous
I like the valuable information you supply in your articles.
I’ll bookmark your blog and take a look at again right here regularly. I’m quite sure I’ll be told many new stuff right right here! Best of luck for the next!
Tammie
Hi, just wanted to say, I enjoyed this blog post.
It was practical. Keep on posting!
Arnoldo
Only wanna state that this is worthwhile, Appreciate taking
your time and energy to this.