A backup that lives on the same server as the site protects you from mistakes, not disasters. If the hosting account gets suspended, hacked, or just goes away, the backup goes with it. Offsite means a second copy in storage you control somewhere else — and automated means it happens at 2 a.m. without you. Before this lesson, you should have a backup you’ve actually restored and a working cron job. You’ll also need an account at some storage provider — Backblaze B2, Amazon S3, even a Google Drive works — rclone speaks to about seventy of them.
Script the dump-and-archive you already do by hand
Put your manual backup steps in a file so cron can run them. Create
/home/you/bin/backup.sh (adjust paths and credentials to your setup):
#!/bin/bash
set -euo pipefail
STAMP=$(date +%Y-%m-%d)
BACKUP_DIR=/home/you/backups
mysqldump --single-transaction example_db | gzip > "$BACKUP_DIR/db-$STAMP.sql.gz"
tar -czf "$BACKUP_DIR/files-$STAMP.tar.gz" -C /var/www/example .
Then make it executable and run it once by hand:
chmod +x /home/you/bin/backup.sh
/home/you/bin/backup.sh
The set -euo pipefail line makes the script stop at the first error
instead of cheerfully continuing — you want a loud failure, not a quiet
half-backup.
Set up rclone against your offsite storage
Install rclone and walk through its interactive setup:
curl https://rclone.org/install.sh | sudo bash
rclone config
Pick n for a new remote, name it something plain like offsite, choose
your provider from the list, and paste in the keys from your storage
account. Then prove the connection works:
rclone lsd offsite:
If that lists your buckets (or an empty nothing, on a fresh account), you’re connected.
Add the copy step to the script
Two more lines at the bottom of backup.sh:
rclone copy "$BACKUP_DIR" offsite:example-backups --include "*-$STAMP.*"
copy uploads without deleting anything at the destination — the gentle
verb. Run the script again by hand and confirm the files landed:
rclone ls offsite:example-backups
Schedule it with cron
Open your crontab and give the script a nightly slot, with output going to a log you can read later:
30 2 * * * /home/you/bin/backup.sh >> /var/log/backup.log 2>&1
Pick an hour when the site is quiet — the database dump does real work.
Rotate old backups automatically
Nightly backups pile up until they fill the disk or the storage bill.
Add a rolling thirty-day window to the end of backup.sh:
find "$BACKUP_DIR" -name "*.gz" -mtime +7 -delete
rclone delete offsite:example-backups --min-age 30d
That keeps a week locally and a month offsite. Before trusting the offsite
half, run it once with --dry-run appended and read what it would
delete — rclone is a good dog, but you check the leash before the walk.
Verify tomorrow that tonight’s run happened
The morning after the first scheduled run, check three things. The log shows a clean finish:
tail -20 /var/log/backup.log
The offsite storage has a file dated today:
rclone ls offsite:example-backups | grep $(date +%Y-%m-%d)
And — once, now, and again every few months — pull one down and restore it, exactly as you practiced in the restore lesson. An offsite backup you’ve never restored from is a rumor. One you have is a plan.