Simple cPanel Backup Rotation Script

Cpanel Backup Rotation

cPanel has a brilliant backup facility built in, however it only keeps 1 backup per backup type. So if you have daily backups enabled running every day of the week, your previous day's backup will be lost - the same applies to weekly and monthly backups.

This can be a bit of a nuisance if you need to restore a file deleted the day before a backup ran.

So using a simple script that hooks into cPanel's backup script, you can retain backups for any number of days, weeks or months and it will only consume a very minimal amount of space - as the script uses hard links. So only the files that have changed will actually take up disk space.

Backup rotation script

Create a new file /scripts/postcpbackup.sh and put the following in it. You can customise the types of backups to be rotated and the retention period.

#!/bin/sh
# Simple backup directory rotation script for cPanel

# Allows daily, weekly and monthly backups to be kept for X number of days using
hard links for retained backup copies, so disk space usage is extremely minimal
#
# Courtesy of www.SonassiHosting.com - The Magento Hosting experts
# Eg. /backup/cpbackup
BACKUP_ROOT_DIR=/backup/cpbackup
# Eg. daily weekly monthly
BACKUP_TYPES=( daily weekly )
# Eg. 1440 10080 40320 - the number of minutes for each respective backup type
BACKUP_AGE=( 1440 10080 )
# Eg. 7 4 1 - How many historical versions to keep of each backup
BACKUP_RETENTION=( 3 1 )

#######################################
Do not edit anything below this line
#######################################
BACKUP_DATE=date +%F
for (( i = 0 ; i < ${#BACKUP_TYPES[@]} ; i++ )); do
TYPE=${BACKUP_TYPES[$i]}
AGE=${BACKUP_AGE[$i]}
RETENTION=${BACKUP_RETENTION[$i]}
MAX_AGE=expr $RETENTION \* $AGE
MIN_AGE=expr $AGE + 60
if [ ! -d $BACKUP_ROOT_DIR/$TYPE ] || [[ ! find $BACKUP_ROOT_DIR/$TYPE_* -maxdepth 1 -mmin -$MIN_AGE -type d == "" ]]; then
echo "DIR '$TYPE' doesn't exist or previous backup too young ($AGE mins)"
continue
fi
Remove oldest backup
find $BACKUP_ROOTDIR/$TYPE* -maxdepth 1 -type d -mmin +$MAX_AGE -exec rm -rf {} ; > /dev/null 2>&1
mkdir -p $BACKUP_ROOTDIR/$TYPE$BACKUP_DATE
Synchronise files
rsync -a --delete
--link-dest=$BACKUP_ROOT_DIR/$TYPE $TYPE/. $BACKUP_ROOTDIR/$TYPE$BACKUP_DATE/
done

Backup restoration from rotation

Just bear in mind, this code does not integrate into the backup restoration aspect of cPanel - so if you do need to restore/find a file - you will have to rename the folders appropriately.

Eg. to restore a daily backup from 2012-04-03

cd /backups/cpbackup
mv daily{,.previous}
mv daily_2012-04-03 daily

Then use the standard restoration tool in WHM, after the restore is complete, just move the folders back to how they were

mv daily daily_2012-04-03
mv daily.previous daily
  • Chris

    Hi, I was wondering if it would be possible to make this script save two weekly backups, 2 monthly and a six monthly - but based only on one weekly backup?

    My problem is that I can only run the backup on one specific day of the week, so in the backup config in WHM, if I choose to save daily, weekly and monthly backups, but set this to run on a Monday, cpanel will backup the daily and weekly backup on that day and It totally ignores the monthly - so I would end up with two backups the same each week and no monthly. I now only select "Daily" and the day of the week, which gives me a weekly backup that is overwritten on that schedule, but this isnt enough.

    If I used your script, I would only be able to save X number of "daily" backups which would actually be weekly ones. S if I chose to save six daily backups, I would get six weekly backups. This is better than nothing, but I'd really like to spread them out more...

    What I really want to do is copy out that single weekly backup so I retain one current backup, one from the previous week, one a month old, one two months old and one six months old - but I have no idea how to do that.

    How easy would it be to adapt your script to do that? I hope you can help

  • BBarberi

    Hi,
    thanks for this very useful script.

    Because the script was not executed on the cpbackup folder, I had to change the rsync command to
    rsync -a --delete
    --link-dest=$BACKUP_ROOT_DIR/$TYPE $BACKUP_ROOT_DIR/$TYPE/. $BACKUP_ROOT_DIR/$TYPE_$BACKUP_DATE/