Skip to content

Instantly share code, notes, and snippets.

@tylercubell
Created July 30, 2020 18:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tylercubell/05c90700a917cf679f481a5ced48bdac to your computer and use it in GitHub Desktop.
Save tylercubell/05c90700a917cf679f481a5ced48bdac to your computer and use it in GitHub Desktop.
WordPress backup script.
#!/bin/bash
# Variables.
backup_dir="backups"
files_dir="/var/www/yoursite" # Don't add trailing slash.
max_backups=14 # Two weeks.
database_name="yoursite"
timezone="US/Eastern"
# Check if script is running as root.
if [ "$EUID" -ne 0 ]; then
echo "Please run as root."
exit
fi
# Automatically create cron entry.
path_to_script=$(realpath $BASH_SOURCE)
filename=`basename "$0"`
# If cron entry doesn't exist.
if ! crontab -l | grep -q $filename; then
echo "Adding cron entry..."
crontab -l > cron
if [[ ! -f "cron" ]]; then
echo "Unable to create cron file."
exit
fi
# Every day at 3 AM.
echo "0 3 * * * $path_to_script" >> cron
crontab cron
rm cron
fi
# Sanity checks.
if [ "$backup_dir" = "" ]; then
echo "Backup directory can't be empty."
exit
elif [ "$backup_dir" = "/" ]; then
echo "Backup directory can't be root directory."
exit
fi
if [[ ! -d "$files_dir" ]]; then
echo "Files directory doesn't exist."
exit
fi
mysql_data_dir=$(mysql -N -B -e "select @@datadir;")
if [[ ! -d "$mysql_data_dir$database_name" ]]; then
echo "Database doesn't exist."
exit
fi
# Create backup directory if it doesn't already exist.
mkdir -p $backup_dir
if [[ ! -d "$backup_dir" ]]; then
echo "Unable to create backup directory."
exit
fi
# Remove old backups.
while true; do
# Count number of backup files in backups directory.
backup_files=($backup_dir/*.tar.gz)
backup_count=${#backup_files[@]}
# Number of backups exceeds limit.
if [ "$backup_count" -gt "$max_backups" ]; then
echo "Backup limit exceeded."
oldest_file=$(find $backup_dir -type f -name '*.tar.gz' -printf '%T+ %f\n' | sort | head -n 1 | awk '{print $2}')
# Sanity check. Make sure file extension is correct before deleting.
if [ "${oldest_file: -7}" = ".tar.gz" ]; then
echo "Deleting $oldest_file..."
rm -f $backup_dir/$oldest_file
fi
# Backup limit not exceeded.
else
break
fi
done
# Create temporary directory for backup.
uuid=$(uuidgen)
now=$(TZ=":$timezone" date)
now=${now// /-} # Replace spaces with hyphens.
now=${now//:/-} # Replace colons with hyphens.
temp_dir="${now}_$uuid"
mkdir -p $backup_dir/$temp_dir
if [[ ! -d "$backup_dir/$temp_dir" ]]; then
echo "Unable to create temporary directory."
exit
fi
# Backup MySQL database.
echo "Dumping MySQL database..."
mysqldump $database_name > $backup_dir/$temp_dir/database.sql
# Copy files before archiving.
# Avoids tar "file changed as we read it" error for live sites.
echo "Copying web files..."
mkdir -p $backup_dir/$temp_dir/files
rsync -a $files_dir/ $backup_dir/$temp_dir/files
# Backup files.
echo "Archiving web files..."
# Add web files to 'files' folder in archive.
tar -C $backup_dir/$temp_dir -cf $backup_dir/$temp_dir/backup.tar files
# Append database to end of archive.
echo "Append database to archive..."
tar -C $backup_dir/$temp_dir -rf $backup_dir/$temp_dir/backup.tar database.sql
# Compress archive with gzip.
echo "Compressing archive..."
gzip $backup_dir/$temp_dir/backup.tar
# Clean up temp files.
echo "Cleaning up..."
# Move archive to main backups directory.
mv $backup_dir/$temp_dir/backup.tar.gz $backup_dir/$temp_dir.tar.gz
# Remove temp directory.
# Todo: add sanity check to make sure fs isn't wiped out.
rm -rf $backup_dir/$temp_dir
# Done.
echo "Done!"