Just putting this here for easy reference, or to help any random passers by. I know there are tools that are supposed to automate this like rsnapshot but I was disappointed to see that rsnapshot is probably unmaintained
On top of that, this looked like something easy enough to roll my own and adapt to my needs. So there you go...
#!/bin/bash
# A script to perform daily/weekly/monthly backups using rsync
SOURCE="user@remote:/path/some_files"
DESTINATION="/backups/my_backups"
# How many backups of each type shall we keep?
DAILY_COUNT=7
WEEKLY_COUNT=4
MONTHLY_COUNT=18
DAILY=$(date "+daily_%Y_%m_%d")
WEEKLY=$(date "+weekly_%Y_%W")
MONTHLY=$(date "+monthly_%Y_%m")
ARCHIVE="archive"
LATEST="latest"
set -e
# Make sure destination dirs exist
mkdir -p "${DESTINATION}/${ARCHIVE}"
mkdir -p "${DESTINATION}/${LATEST}"
cd "${DESTINATION}"
ABS_LATEST="$(pwd)/${LATEST}"
# Do the rsync
rsync -a --quiet --delete --link-dest="${ABS_LATEST}" -- "${SOURCE}" "${ARCHIVE}/${DAILY}"
# Replace the last latest
/bin/rm -rf -- "${ABS_LATEST}"
/bin/cp -al -- "${ARCHIVE}/${DAILY}" "${ABS_LATEST}"
# Add new weekly if needed
if [ ! -d "${ARCHIVE}/${WEEKLY}" ]; then
/bin/cp -al -- "${ABS_LATEST}" "${ARCHIVE}/${WEEKLY}"
fi
# Add new monthly if needed
if [ ! -d "${ARCHIVE}/${MONTHLY}" ]; then
/bin/cp -al -- "${ABS_LATEST}" "${ARCHIVE}/${MONTHLY}"
fi
# Cull archives
cd "${ARCHIVE}"
# Daily culling
/usr/bin/find . -maxdepth 1 -type d -regextype posix-egrep \
-regex ".*\/daily_[0-9]{4}_[0-9]{2}_[0-9]{2}" -printf "%f\n" |
sort -r |
tail -n +$((${DAILY_COUNT} + 1)) |
while read EXPIRED; do
#echo "Removing ${EXPIRED}"
/bin/rm -rf -- "$EXPIRED"
done
# Weekly culling
/usr/bin/find . -maxdepth 1 -type d -regextype posix-egrep \
-regex ".*\/weekly_[0-9]{4}_[0-9]{2}" -printf "%f\n" |
sort -r |
tail -n +$((${WEEKLY_COUNT} + 1)) |
while read EXPIRED; do
#echo "Removing ${EXPIRED}"
/bin/rm -rf -- "$EXPIRED"
done
# Monthly culling
/usr/bin/find . -maxdepth 1 -type d -regextype posix-egrep \
-regex ".*\/monthly_[0-9]{4}_[0-9]{2}" -printf "%f\n" |
sort -r |
tail -n +$((${MONTHLY_COUNT} + 1)) |
while read EXPIRED; do
#echo "Removing ${EXPIRED}"
/bin/rm -rf -- "$EXPIRED"
done