Skip to content

Instantly share code, notes, and snippets.

@andy-berry-dev
Last active August 26, 2015 21:24
Show Gist options
  • Save andy-berry-dev/f9fa1a8d21e6eb42fa8f to your computer and use it in GitHub Desktop.
Save andy-berry-dev/f9fa1a8d21e6eb42fa8f to your computer and use it in GitHub Desktop.
backup script for digital ocean VM

A LAMP server backup script

A script to backup MySQL databases and website data. Backs up all databases to individual gzipped files and each directory in WWW_DATA_DIR to individual gzipped tar archives.

  • backup_env.sh is used to set the neccessary config. This must exist next to the backup script.
  • Use the example here as a starting point.
  • backup.sh is the script itself. Download an execute using ./backup.sh.
  • You're probably using this on a production server. MAKE SURE YOU KNOW WHAT IT WILL EXECUTE!
  • Set DRY_RUN to anything other than 'false' to check what commands will execute.

Can be added as a cronjob. For example to backup at midnight where the script exists in /BACKUP use:

@midnight /BACKUP/backup.sh >/dev/null

THIS SCRIPT WAS WRITTEN TO SATISFY MY OWN NEEDS. IT HAS BEEN TESTED AND SEEMS TO WORK. I ACCEPT NO RESPONSIBILITY FOR LOST DATA.

#!/bin/sh
set -e
# THIS SCRIPT WAS WRITTEN TO SATISFY MY OWN NEEDS. IT HAS BEEN TESTED AND SEEMS TO WORK. I ACCEPT NO RESPONSIBILITY FOR LOST DATA.
cd "$(dirname "$0")"
ENV_FILENAME="./backup_env.sh"
if [ ! -x "$ENV_FILENAME" ]
then
echo "Environment variable file '$ENV_FILENAME' does not exist or is not executable" >&2
exit 1;
fi
echo "loading environment variables from ${ENV_FILENAME}"
. ${ENV_FILENAME}
if [ $? -ne 0 ]
then
echo "Environment variable file '$ENV_FILENAME' failed to execute" >&2
exit 1;
fi
: ${DRY_RUN:?"variable must be set to either TRUE or FALSE"}
: ${BACKUP_DIR:?"variable must be set"}
: ${DB_USER:?"variable must be set"}
: ${DB_PASS:?"variable must be set"}
: ${DB_HOST:?"variable must be set"}
: ${WWW_DATA_DIR:?"variable must be set"}
: ${BACKUP_RETENTION_DAYS:?"variable must be set"}
: ${TIMESTAMP:?"variable must be set"}
DB_BACKUP_DIR="${BACKUP_DIR}/dbbackup"
SITES_BACKUP_DIR="${BACKUP_DIR}/sitebackup"
if [ "${DRY_RUN}" != false ] ; then
echo "DRY_RUN flag was not 'false', no commands will be executed that could have bad outcomes"
RUN="echo RUN COMMMAND:"
else
echo "DRY_RUN was 'false', REAL COMMANDS WILL BE USED"
RUN=""
fi
if [ ! -d "${BACKUP_DIR}" ]
then
echo "Backup directory ${BACKUP_DIR} did not exist or was not a directory" >&2
exit 1;
fi
echo "performing backup at ${TIMESTAMP}"
$RUN mkdir -p ${DB_BACKUP_DIR}
echo "database backup destination is ${DB_BACKUP_DIR}"
$RUN mkdir -p ${SITES_BACKUP_DIR}
echo "site backup destination is ${SITES_BACKUP_DIR}"
echo "performing backup for databases on server ${DB_HOST}"
databases=$(mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASS} -e "SHOW DATABASES;" | tr -d "| " | grep -Ev "(Database|information_schema|performance_schema)");
databases_singleline="$(echo "$databases" | tr '\n' ' ')"
echo "found databases: ${databases_singleline}"
for db in $databases; do
echo " performing mysqldump for db ${db}"
db_backup_filename="${DB_BACKUP_DIR}/${TIMESTAMP}_${db}.sql"
echo " using environment variable for pass"
export MYSQL_PWD=$DB_PASS
$RUN mysqldump --force --opt --add-drop-table -u ${DB_USER} --databases ${db} --result-file=${db_backup_filename}
$RUN gzip ${db_backup_filename}
echo " database backup written to ${db_backup_filename}.gz"
done
echo "performing backup for site data in ${WWW_DATA_DIR}"
cd ${WWW_DATA_DIR}
site_dirs=`ls -d */ | sed 's#/##'`
site_dirs_singleline="$(echo "$site_dirs" | tr '\n' ' ')"
echo "found site data dirs: ${site_dirs_singleline}"
for site_dirname in $site_dirs; do
echo " creating archive for ${site_dirname}"
site_tar_filename=" ${SITES_BACKUP_DIR}/${TIMESTAMP}_${site_dirname}.tar.gz"
$RUN tar -czf ${site_tar_filename} ${site_dirname}
echo " site backup archive written to ${site_tar_filename}"
done
echo "cleaning up backups older than ${BACKUP_RETENTION_DAYS} days from ${DB_BACKUP_DIR}"
$RUN find ${DB_BACKUP_DIR} -mtime +${BACKUP_RETENTION_DAYS} -exec rm {} \;
echo "cleaning up backups older than ${BACKUP_RETENTION_DAYS} days from ${SITES_BACKUP_DIR}"
$RUN find ${SITES_BACKUP_DIR} -mtime +${BACKUP_RETENTION_DAYS} -exec rm {} \;
# set to anything other than 'false' to output commands
# that would be run rather than execute commands themselves
export DRY_RUN=true
# the directory to backup to
export BACKUP_DIR=/my/backupdir
# the database user, should have read perms to all databases in order to do the backup
export DB_USER=mysqluser
# the database user's password
export DB_PASS=topsecretpass
# the hostname for the database
export DB_HOST=localhost
# the location of the website files
export WWW_DATA_DIR=/var/www/
# the number of days to keep backups for
export BACKUP_RETENTION_DAYS=30
# the timestamp, use the 'date' command to set a timestamp to any format
export TIMESTAMP=`date +%Y-%m-%d_%H-%M-%S`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment