Posted by & filed under Linux.

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

4 Responses to “Linux Tip: Create a bash script to archive web folders and mysql databases locally and remotely”

  1. 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!

  2. Tammie

    Hi, just wanted to say, I enjoyed this blog post.
    It was practical. Keep on posting!

  3. Arnoldo

    Only wanna state that this is worthwhile, Appreciate taking
    your time and energy to this.

Leave a Reply

  • (will not be published)