Backup Strategies: The 3-2-1 Rule and What Actually Matters
Most backup strategies fail because they were never tested. Here's how to actually implement reliable backups that you'll thank yourself for when things break.
The Backup Reality Check
Backups are like insurance. Everyone knows they need them. Most people don't test them until it's too late. The number of "we had backups" stories that end with "but the last good backup was from three months ago" is embarrassingly high.
This guide isn't about backup tools. It's about backup strategy โ what to back up, how to structure retention, where to store it, and most importantly, how to verify it actually works.
The 3-2-1 Rule
The standard advice, explained properly:
3 copies of your data
2 different storage media
1 offsite
"3 copies" means: your live data + 2 backups. Not one backup. One backup is a single point of failure.
"2 different media" means: if your backup is on the same server as your data and the server dies, you lose both. Better: server disk + external disk, or server disk + cloud storage.
"1 offsite" means: if your office burns down, your backup in the office doesn't help. The offsite copy is your protection against site-level disasters.
3-2-1 in Practice
| Layer | What | Where |
|---|
| Live | Your data | On the server |
|---|---|---|
| Backup 1 | Full snapshot | External disk (same location) |
| Backup 2 | Incremental snapshots | Cloud storage (different location) |
This is the minimum viable setup. You can add more layers (snapshot replication, multi-cloud), but start here.
What to Back Up
Application Data (Always)
- Databases (MySQL, PostgreSQL, MongoDB, etc.)
- User-uploaded files (images, documents, media)
- Configuration files (if modified from defaults)
- Application secrets (but encrypt them โ don't store plaintext keys in S3)
- Web server configs: probably, yes
- System packages: no (you can reinstall)
- OS: no (reinstall is faster and cleaner)
- Logs: optional (compress and rotate if disk allows)
- Temporary files โ
/tmp, cache directories - Build artifacts โ
node_modules,.git, build outputs (can be rebuilt) - Large media files that can be re-downloaded โ if your server downloads public datasets, consider if you need to back up the download or just the download script
System Data (Depends)
What Not to Back Up
Backup Methods
Database dumps
# MySQL/MariaDB
mysqldump --single-transaction --routines --triggers --all-databases | gzip > /backups/mysql_all_$(date +%Y%m%d).sql.gz# PostgreSQL
pg_dumpall | gzip > /backups/postgres_all_$(date%Y%m%d).sql.gz
# MongoDB
mongodump --archive=/backups/mongo_$(date +%Y%m%d).archive --gzip
Dumps should happen with --single-transaction (MySQL) or equivalent to ensure consistency without locking the database.
Filesystem snapshots
# rsync with hardlinks (for incremental efficient copies)
rsync -avz --delete /var/www/ /backup-disk/www/# With hardlinks for space efficiency (each daily backup only stores changes)
rsync -avz --delete --link-dest=/backup-disk/www-day-1 /var/www/ /backup-disk/www-day-2/
LVM snapshots
If your server uses LVM, you can take instant snapshots:
# Create snapshot (instant, not copy)
lvcreate --size 10G --snapshot --name backup-snap /dev/vg0/lv-root# Mount and backup
mount /dev/vg0/backup-snap /mnt/snapshot
# After backup
umount /mnt/snapshot
lvdelete /dev/vg0/backup-snap
LVM snapshots are space-efficient (copy-on-write) and fast to create. They're ideal for consistent database backups without downtime.
Retention Policies
Retention is the hard part. Keep backups too short, and you might not have a clean version to restore from. Keep them too long, and storage costs spiral.
Recommended Retention
| Type | Frequency | Retention |
|---|
| Full backup | Daily | 7 days (daily) |
|---|---|---|
| Weekly backup | Weekly | 4 weeks |
| Monthly backup | Monthly | 12 months |
| Annual backup | Yearly | 7 years |
For most projects, this covers:
- "I need last night's backup" (daily)
- "Something broke last week, what did it look like?" (weekly)
- "We need to see data from 3 months ago" (monthly)
- "Audit requires records from 7 years ago" (annual)
- Daily backups (Son): Keep 6 daily
- Weekly backups (Father): Keep 4 weekly
- Monthly backups (Grandfather): Keep 12 monthly
Simplify: The GFS Approach
Grandfather-Father-Son is a rotation scheme that simplifies retention:
This gives you 6 recent days, 4 weeks, and 12 months. For most projects, this is sufficient.
#!/bin/bash
# /usr/local/bin/backup-rotate.shBACKUP_DIR="/backup-disk"
DATE=$(date +%Y%m%d)
DAY=$(date +%a)
WEEK=$(date +%G-%V)
MONTH=$(date +%Y-%m)
# Daily backup
tar -czf $BACKUP_DIR/daily/$DATE.tar.gz /var/www /etc/nginx /var/lib/mysql
# Weekly if Sunday
if [ "$DAY" = "Sun" ]; then
cp $BACKUP_DIR/daily/$DATE.tar.gz $BACKUP_DIR/weekly/week-$WEEK.tar.gz
fi
# Monthly if first of month
if [ "$(date +%d)" = "01" ]; then
cp $BACKUP_DIR/daily/$DATE.tar.gz $BACKUP_DIR/monthly/month-$MONTH.tar.gz
fi
# Cleanup old daily backups (keep 7 days)
find $BACKUP_DIR/daily -name "*.tar.gz" -mtime +7 -delete
Offsite Storage
Cloud Options
| Provider | Service | Cost (approx) | Notes |
|---|
| AWS | S3 | $0.023/GB/mo (Standard) | Most mature, egress costs |
|---|---|---|---|
| B2 | Backblaze | $0.006/GB/mo | No egress fees, S3-compatible |
| Wasabi | Wasabi | $0.007/GB/mo | No egress fees, S3-compatible |
| R2 | Cloudflare | $0.015/GB/mo | No egress fees, S3-compatible |
For most use cases, Backblaze B2 or Wasabi offer the best value. S3 is the standard but has egress fees that can surprise you.
Upload Tools
# rclone (supports B2, S3, Wasabi, R2, and more)
rclone copy /backup-disk/daily/$DATE.tar.gz b2:my-bucket/daily/# With bandwidth limiting to avoid saturating connection
rclone copy --bwlimit 10M /backup-disk/daily/$DATE.tar.gz b2:my-bucket/daily/
# AWS CLI (if using S3)
aws s3 cp /backup-disk/daily/$DATE.tar.gz s3://my-bucket/daily/
Encryption Before Upload
Never upload unencrypted backups to the cloud. Use gpg or rclone's built-in encryption:
# Encrypt with a password (use a passphrase, not a key file)
gpg --encrypt --recipient "Backup Key" /backup-disk/daily/$DATE.tar.gz# Or use rclone's encryption (simpler for rclone-native operations)
rclone --crypt-password "mypassword123" copy /backup-disk/daily/ b2:encrypted-backups/
The Part Everyone Skips: Testing Restores
Backups are worthless if you can't restore from them. Schedule regular restore tests.
What to Test
1. File restore โ Can I extract a specific file from a backup? 2. Database restore โ Can I restore a database dump to a test server? 3. Full restore โ Can I rebuild a server from scratch using only backups?
Restore Test Schedule
- Weekly: Verify one file restore works
- Monthly: Restore a database to a test environment
- Quarterly: Full disaster recovery drill
Restore Test Script
#!/bin/bash
# /usr/local/bin/test-restore.shBACKUP=/backup-disk/daily/$(date -d "yesterday" +%Y%m%d).tar.gz
TEST_DIR=/tmp/restore-test
# Extract to test directory
mkdir -p $TEST_DIR
tar -xzf $BACKUP -C $TEST_DIR
# Verify key files exist
if [ -f $TEST_DIR/var/www/wp-config.php ]; then
echo "โ WordPress config found"
else
echo "โ WordPress config MISSING"
exit 1
fi
# Verify database dump
if [ -f $TEST_DIR/var/lib/mysql/latest.sql.gz ]; then
echo "โ Database dump found"
else
echo "โ Database dump MISSING"
exit 1
fi
# Cleanup
rm -rf $TEST_DIR
echo "โ Restore test passed"
Automation
Cron Schedule Example
# Daily backup at 3am
0 3 * /usr/local/bin/backup.sh# Upload to cloud at 4am
0 4 * /usr/local/bin/backup-upload.sh
# Test restore at 9am Monday
0 9 1 /usr/local/bin/test-restore.sh
# Cleanup old local backups (keep 7 days)
0 5 find /backup-disk -name ".tar.gz" -mtime +7 -delete
What to Do When Restoring
When disaster strikes:
1. Assess the scope. Full server loss vs single file vs database corruption? Different scenarios, different restore procedures.
2. Identify the restore point. When was the last known good backup? Factor in how much data you're willing to lose.
3. Restore to a test environment first. Don't overwrite production until you've verified the backup is good.
4. Communicate. If users are affected, tell them. "We had a failure and we're restoring from backup, ETA X hours" is better than silence.
5. Post-mortem. What failed? Was it the backup system, the monitoring, or the underlying cause? Fix the root cause, not just the symptom.
The Checklist
Before you call your backup strategy done:
- [ ] All databases being dumped daily
- [ ] Dump files compressed and stored safely
- [ ] File backups using rsync or similar
- [ ] Retention policy defined and implemented
- [ ] Offsite copy exists (cloud or remote server)
- [ ] Backup encryption enabled
- [ ] Monitoring: backup job success/failure alerts
- [ ] Restore tested (file level)
- [ ] Restore tested (database level)
- [ ] Full restore drill done within last quarter
- [ ] Documented restore procedure exists
Backups are not a "set and forget" system. They require maintenance, testing, and occasional intervention. Treat them accordingly.
Rather than DIY? Let OpsHelp handle everything.
Managed hosting with support, security, backups, and monitoring โ from ยฃ50/mo.