Managing backup retention policies manually becomes impractical at scale. We need an automated solution that:
- Preserves daily backups for 7 days
- Keeps weekly backups for 4 weeks
- Retains monthly backups for 12 months
- Archives yearly backups indefinitely
Here's a robust bash script that handles the rotation logic:
#!/bin/bash
# Configuration
BACKUP_DIR="/var/backups"
PREFIX="blog"
RETENTION_DAILY=7
RETENTION_WEEKLY=4
RETENTION_MONTHLY=12
# Create new daily backup
DATE=$(date +%Y%m%d)
tar -cjf "$BACKUP_DIR/$PREFIX-$DATE.tar.bz2" /path/to/data
# Rotation logic
find "$BACKUP_DIR" -name "$PREFIX-*.tar.bz2" | sort | while read file; do
filename=$(basename "$file")
filedate=${filename#$PREFIX-}
filedate=${filedate%.tar.bz2}
# Parse date components
year=${filedate:0:4}
month=${filedate:4:2}
day=${filedate:6:2}
# Convert to epoch for comparison
filedate_epoch=$(date --date="$year-$month-$day" +%s)
now_epoch=$(date +%s)
age_days=$(( (now_epoch - filedate_epoch) / 86400 ))
# Determine backup type
if [ "$day" == "01" ] && [ "$age_days" -gt 365 ]; then
# Yearly backup (keep forever)
continue
elif [ "$day" == "01" ] && [ "$age_days" -le 365 ]; then
# Monthly backup (keep for 12 months)
if [ "$age_days" -gt $((RETENTION_MONTHLY * 30)) ]; then
rm "$file"
fi
elif [ $(date --date="$year-$month-$day" +%u) -eq 1 ] && [ "$age_days" -gt 7 ]; then
# Weekly backup (keep for 4 weeks)
if [ "$age_days" -gt $((RETENTION_WEEKLY * 7)) ]; then
rm "$file"
fi
else
# Daily backup (keep for 7 days)
if [ "$age_days" -gt $RETENTION_DAILY ]; then
rm "$file"
fi
fi
done
Add this to your crontab to run daily at 2 AM:
0 2 * * * /path/to/backup_rotation.sh
To test the rotation logic, create test files with appropriate dates:
# Create sample backup files
touch blog-{20230101..20230131}.tar.bz2
touch blog-{20230201..20230228}.tar.bz2
Then run the script and verify the remaining files match your retention policy.
For production environments, consider adding:
- Logging with timestamps
- Error handling for full disks
- Notification system for failures
- Checksum verification
When implementing enterprise-grade backup retention policies, we need a solution that:
- Preserves recent backups at high frequency (daily)
- Maintains mid-term recovery points (weekly/monthly)
- Archives historical snapshots (yearly)
Here's how we'll structure the backup directory:
/backups/
├── daily/
├── weekly/
├── monthly/
├── yearly/
└── archive/
This Bash script handles the tiered rotation automatically:
#!/bin/bash
# Configuration
BACKUP_NAME="blog"
RETENTION_DAILY=7
RETENTION_WEEKLY=4
RETENTION_MONTHLY=12
BACKUP_DIR="/backups"
# Create new backup
timestamp=$(date +%Y%m%d)
tar -cjf "$BACKUP_DIR/daily/$BACKUP_NAME-$timestamp.tar.bz2" /path/to/data
# Daily to Weekly promotion (every Sunday)
if [ $(date +%u) -eq 7 ]; then
oldest_daily=$(ls -t $BACKUP_DIR/daily/ | tail -1)
cp "$BACKUP_DIR/daily/$oldest_daily" "$BACKUP_DIR/weekly/"
# Cleanup old weekly backups
ls -t $BACKUP_DIR/weekly/ | tail -n +$((RETENTION_WEEKLY+1)) | xargs -I {} rm "$BACKUP_DIR/weekly/{}"
fi
# Weekly to Monthly promotion (first of month)
if [ $(date +%d) -eq 1 ]; then
oldest_weekly=$(ls -t $BACKUP_DIR/weekly/ | tail -1)
cp "$BACKUP_DIR/weekly/$oldest_weekly" "$BACKUP_DIR/monthly/"
# Cleanup old monthly backups
ls -t $BACKUP_DIR/monthly/ | tail -n +$((RETENTION_MONTHLY+1)) | xargs -I {} rm "$BACKUP_DIR/monthly/{}"
fi
# Yearly archive (January 1st)
if [ $(date +%m%d) -eq "0101" ]; then
oldest_monthly=$(ls -t $BACKUP_DIR/monthly/ | tail -1)
cp "$BACKUP_DIR/monthly/$oldest_monthly" "$BACKUP_DIR/yearly/"
fi
Add this to crontab (runs daily at 2AM):
0 2 * * * /path/to/backup_script.sh
To check your backup structure:
# Show retention counts
echo "Daily: $(ls /backups/daily | wc -l)"
echo "Weekly: $(ls /backups/weekly | wc -l)"
echo "Monthly: $(ls /backups/monthly | wc -l)"
echo "Yearly: $(ls /backups/yearly | wc -l)"
For production environments, consider adding:
- MD5 checksum verification
- Remote sync to cloud storage
- Email notifications on failure
- Log rotation for the script itself