How to Automate Server Backups (and Actually Test Them)
This page may contain affiliate links.
Everyone has a backup plan until the day they need it. The uncomfortable truth is that an untested backup isn't a backup — it's a hope. I've watched a homelabber lose three years of photos because their rsync job had been silently failing for months after a disk UUID changed. The script ran, the cron job fired, the logs said "success", and the destination folder was empty. So this guide is about two things: automating backups properly, and proving they work. Both matter equally.
We'll cover a simple, robust approach you can run on any Linux box — a VPS, a Raspberry Pi, an old Optiplex in the shed — plus a restore drill that takes ten minutes and will save you a very bad weekend.
Start with the 3-2-1 rule, not with a tool
Before you touch a single script, decide what you're actually protecting. The classic framework is 3-2-1: three copies of your data, on two different types of media, with one copy off-site. For a home server that usually means:
- Copy 1: the live data on the server itself.
- Copy 2: a local backup to a USB drive or NAS on your own network.
- Copy 3: an encrypted copy in cloud storage or at a friend's house.
For the local copy, any USB 3.0 external drive will do — a 4TB drive costs roughly the price of a decent takeaway for four people, and you can find a range of options here: external hard drives on Amazon UK. The point isn't the brand, it's that it's a separate device from your server. A second partition on the same disk is not a backup.
Write the script properly (and make it fail loudly)
Here's a minimal but genuinely solid backup script using rsync. Save it as /usr/local/bin/backup.sh and make it executable with chmod +x.
#!/bin/bash
set -euo pipefail
SRC="/srv/data/"
DEST="/mnt/backup/data/"
LOG="/var/log/backup.log"
STAMP=$(date +%Y-%m-%d_%H%M)
echo "[$STAMP] Starting backup" >> "$LOG"
# Snapshot-style copy: hardlinks unchanged files, saves space
rsync -aAXH --delete --link-dest="$DEST/current" \
"$SRC" "$DEST/$STAMP/" >> "$LOG" 2>&1
# Update the 'current' symlink for next run's link-dest
ln -sfn "$DEST/$STAMP" "$DEST/current"
# Keep the last 14 snapshots
cd "$DEST" && ls -1dt */ | grep -v current | tail -n +15 | xargs -r rm -rf
echo "[$STAMP] Backup complete" >> "$LOG"
The set -euo pipefail line is the most important bit. Without it, a failed rsync can still exit zero and your cron job will happily report success. This makes the script stop the moment anything goes wrong.
The --link-dest trick gives you cheap incremental snapshots: unchanged files become hardlinks, so fourteen daily snapshots of a 500GB dataset might only use 520GB total. You get versioning without the storage cost.
Schedule it with cron — crontab -e and add:
0 3 * * * /usr/local/bin/backup.sh
Get the off-site copy right
A local backup protects you from accidental deletion and disk failure. It does not protect you from a burglary, a flood, or a very enthusiastic toddler. For the off-site leg, rclone is the tool to reach for — it speaks to Backblaze B2, S3, Google Drive, Dropbox and dozens of others with one syntax.
Install it, run rclone config to set up your remote, then add a second cron line:
30 4 * * * rclone sync /srv/data/ remote:server-backup --bwlimit 8M
The --bwlimit 8M caps upload bandwidth so your evening Netflix doesn't stutter. Always encrypt before upload — either use your provider's server-side encryption or, better, rclone's client-side crypt remote so the provider can't read your files.
If you're doing this seriously, an encrypted external SSD for the rotate-and-take-off-site copy is worth considering: encrypted external SSDs are small enough to live in a coat pocket.
Now the bit everyone skips: test the restore
Two-thirds of the way through, this is where most guides wave cheerfully and stop. Don't. A backup you have never restored is a rumour.
Here's a restore drill you can run monthly. First, verify the files exist and aren't zero-byte:
find /mnt/backup/data/current -type f -size 0 | head
An empty result is what you want. Now do a real restore into a scratch directory:
mkdir -p /tmp/restore-test
rsync -aAXH /mnt/backup/data/current/ /tmp/restore-test/
diff -r /srv/data /tmp/restore-test | head -50
If diff is quiet, your backup matches the source. If it isn't, you've just found the problem on a Tuesday afternoon instead of during a crisis.
For databases, a file copy isn't enough — you need a logical dump. For PostgreSQL:
pg_dump -U postgres mydb | gzip > /mnt/backup/db/mydb_$(date +%F).sql.gz
Then actually load it into a throwaway container and run a SELECT COUNT(*) on your biggest table. That's the test that matters.
Finally, wire up a dead man's switch. Healthchecks.io (free tier is plenty) gives you a URL to ping at the end of your script. If the ping doesn't arrive, it emails you. That single line catches silent failures that logs never will:
curl -fsS --retry 3 https://hc-ping.com/YOUR-UUID > /dev/null
Make the setup repeatable
Once you've got this working, resist the urge to hand-tune it forever. Put your scripts in a Git repo, document the restore procedure in a README, and store your credentials in a password manager rather than in the script itself. The whole point of automation is that future-you — the one woken at 2am by a failed disk — doesn't have to remember how any of it works.
If you'd rather not write all this from scratch, the Home Lab & Automation Pack is a set of ready-made AI prompts for scripting, troubleshooting and documenting exactly this kind of setup — useful if you want the done-for-you version of what we've just walked through, from £9.
Conclusion
Automated backups are one of those rare bits of home lab work that pay off enormously the one time you need them. Get the 3-2-1 structure right, write a script that fails loudly, push an encrypted copy off-site, and — this is the part that separates the prepared from the hopeful — restore something on purpose every month. Set a calendar reminder now. Your future self, staring at a dead drive, will thank you.
SEO Content Briefs with ChatGPT: A Step-by-Step Workflow
Stop staring at a blank doc. Here's a practical, repeatable workflow for building SEO content briefs with ChatGPT that writers actually want to use.
AI Prompts for Newsletters People Actually Open
Most newsletters die in the inbox graveyard because the subject line is dull and the first line is worse. Here are the exact AI prompts that fix both — plus the rest of the email.
How to Repurpose One Blog Post into 10 Pieces of Content
Write once, publish everywhere. A practical UK-focused workflow for turning a single blog post into ten distinct pieces of content, with prompts you can copy and paste.