The Internet is full with backup scripts, using tar and create a backup file, but most of them just creates the archive and that’s all. I also wanted to keep only a limited number of archives in my backup folder. And also the ability to handle archives from the file system and from other sources such as database backups.

Configuration

The script has the following configuration options:

  • DIRECTORIES: list of the directories to back up
  • BACKUPDIR: location of the backup files
  • THRESHOLD: date while keep old archives

Scheduling

I placed the script to the /etc/cron.daily directory, but it should work with other scheduling configuration.

Source

#!/usr/bin/env bash
##
## Creates a backup archive from the specified directories, and removes expired
## ones.
##
## Change the following variables before use:
##      DIRECTORIES: list of the directories to back up
##      BACKUPDIR: location of the backup files
##      THRESHOLD: date while keep old archives

# directories to backup
DIRECTORIES="/etc /boot /home/srv/webapps"
# where to store the backups
BACKUPDIR=/backup
# base part of the backup file is generated by the current date
BACKUPFILE=$(date +%Y%m%d%H%M)
# the threshod date wile the script should keep backup archives
THRESHOLD=$(date -d "30 days ago" +%Y%m%d%H%M)

# Create the archive using tar.
tar -cvpzf $BACKUPDIR/$BACKUPFILE.tar.gz $DIRECTORIES

# Additional backup commands can be added, such as database backup
# but similar file naming convention should be used, but filename
# should start with $BACKUPFILE and ends with .tar.gz
echo "Backing up postgres databases..."
sudo -u postgres pg_dumpall | gzip > $BACKUPDIR/$BACKUPFILE.postgres.tar.gz

# Remove old backups base on the THRESHOLD variable.
echo "Removing old backup files."
find ${BACKUPDIR} -maxdepth 1 -type f -print0  | while IFS= read -d '' -r file
do
    ## Does this file name match the pattern (13 digits.*.tar.gz)?
    if [[ "$(basename "$file")" =~ ^[0-9]{12}.*.tar.gz$ ]]
    then
        ## Delete the file if it's older than the $THRESHOLD
        if [ "$(basename $file | cut -d'.' -f1)" -le "$THRESHOLD" ]
        then
            echo "$file is older than threshold, deleting..."
            rm -v -- "$file"
        fi
    fi
done