Your VPS is fine right now. That's exactly the problem — nobody sets up real backups on a healthy server, and by the time the disk fails, the provider's data center floods, or a bad rm -rf takes out /var/www, it's too late to start. If your only backup plan is a snapshot from your hosting provider, you have a single point of failure: it lives on the same infrastructure as the server it's protecting. This guide walks through setting up automated, off-site backups on a VPS using cron and rclone — free tools, a script you control, and a copy of your data that survives even if the entire VPS disappears.
Why a Snapshot Alone Isn't a Backup Strategy
A provider snapshot is great for one thing: rolling back a bad kernel update or a botched software install in minutes. But snapshots usually live in the same account, sometimes the same data center, as the VPS itself. If your account gets suspended, the provider has an outage, or you fat-finger a "delete server" button, the snapshot can go with it.
Real disaster recovery needs a copy of your data somewhere else entirely — a different provider, a different region, ideally a different company. That's what this setup gives you: your website files and database dumped, compressed, and pushed to off-site storage every night, without you touching a keyboard.
What You Need Before You Start
- SSH access to your VPS with a sudo-capable user (not logging in as
rootdirectly — see our SSH hardening guide if you haven't set that up yet) - An off-site storage destination: Backblaze B2, AWS S3, or even a Google Drive/Dropbox account with enough free space. B2 is the cheapest for pure backup storage.
- MySQL/MariaDB credentials for the database(s) you want backed up
- 10–15 minutes of downtime-free setup — none of this touches your live site
Step 1: Install Rclone
Rclone is a single binary that talks to almost every cloud storage provider using one consistent syntax. Install it with the official script:
curl https://rclone.org/install.sh | sudo bashConfirm it installed correctly:
rclone versionStep 2: Configure a Remote
Run the interactive config wizard:
rclone configChoose n for a new remote, name it something memorable like b2backup, then pick your provider from the list (Backblaze B2, Amazon S3, Google Drive, etc.) and follow the prompts for your access key and secret. When it's done, test the connection:
rclone lsd b2backup:If that lists your bucket (or comes back empty with no error), the remote is working.
Step 3: Write the Backup Script
Create a script that dumps your database, archives your site files, and pushes both off-site. Save this as /root/scripts/backup.sh:
#!/bin/bash
set -e
DATE=$(date +%F)
BACKUP_DIR="/root/backups/$DATE"
SITE_DIR="/var/www/html"
DB_NAME="your_database"
DB_USER="your_db_user"
DB_PASS="your_db_password"
REMOTE="b2backup:my-site-backups"
mkdir -p "$BACKUP_DIR"
# Dump the database
mysqldump -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" | gzip > "$BACKUP_DIR/db.sql.gz"
# Archive site files
tar -czf "$BACKUP_DIR/files.tar.gz" -C "$SITE_DIR" .
# Push to off-site storage
rclone copy "$BACKUP_DIR" "$REMOTE/$DATE" --transfers=4
# Clean up local copy older than 3 days to save disk space
find /root/backups/* -maxdepth 0 -type d -mtime +3 -exec rm -rf {} \;
# Delete remote backups older than 30 days
rclone delete --min-age 30d "$REMOTE"
Make it executable:
chmod +x /root/scripts/backup.shNever hardcode the DB password in a world-readable file. Lock the script down with chmod 700 and keep it under /root, or better, read credentials from a separate .my.cnf file mysqldump picks up automatically.
Step 4: Schedule It with Cron
Open the root crontab:
sudo crontab -eAdd a line to run the backup every night at 2 AM server time:
0 2 * * * /root/scripts/backup.sh >> /var/log/backup.log 2>&1The >> /var/log/backup.log 2>&1 part matters — without it, cron silently swallows both the output and any errors, and you won't know the backup stopped working until you actually need it.
Cron Schedule Reference
| Schedule | Cron Expression | Good For |
|---|---|---|
| Nightly | 0 2 * * * | Most WordPress/small business sites |
| Every 6 hours | 0 */6 * * * | Active WooCommerce stores, frequent content changes |
| Weekly | 0 3 * * 0 | Mostly-static sites, low write volume |
Step 5: Actually Test the Restore
This is the step almost everyone skips, and it's the one that matters most. A backup you haven't restored is a guess, not a backup. Pick a quiet moment and run through it once:
- Pull a backup down:
rclone copy b2backup:my-site-backups/2026-07-14 /tmp/restore-test - Spin up a throwaway database and import the dump:
gunzip -c db.sql.gz | mysql -u root -p test_restore_db - Extract the files archive to a scratch directory and spot-check that
wp-config.php, uploads, and plugin folders are all there - Time how long the whole process took — that number is your real recovery time, not a guess
Do this test once after setup and then again every few months. Storage providers change APIs, disks fill up, and scripts silently break — you want to find that out on a Tuesday afternoon, not during an actual outage.
Prevention: Keep the Backup Pipeline Honest
- Alert on failure, not just success. Add a simple check at the end of the script that pings a monitoring service (like a healthchecks.io URL) only if the previous commands succeeded — you'll get notified the moment a night's backup silently fails.
- Watch disk usage. Local temp copies before the off-site push can fill the disk fast on a busy store. The cleanup line in the script above handles this, but check
df -hoccasionally. - Keep at least one backup outside your Getwebup account entirely. If the goal is surviving a worst-case scenario, the backup can't live in the same blast radius as the thing it protects.
- Encrypt sensitive dumps. If your database contains customer data, pipe the dump through
gpgbefore it leaves the server, or use rclone's built-in crypt remote.
Snapshots vs. This Setup
These two aren't competing — they cover different failure modes. Keep both:
| Provider Snapshot | Cron + Rclone Off-Site Backup | |
|---|---|---|
| Speed to restore | Minutes, whole server | Slower, file/database level |
| Survives account/provider loss | No | Yes |
| Good for | Undoing a bad update or config change | Disaster recovery, migration, ransomware/hack recovery |
| Granularity | Full disk only | Pick specific files or database tables to restore |
Need this done for you instead of scripting it yourself? Getwebup's managed VPS plans include off-site backup configuration as part of onboarding — open a ticket and we'll set the whole pipeline up on your server.