Disclosure: we may earn a commission or referral reward from CloudCone, Contabo, DigitalOcean (account credit, not cash), Hostwinds, InterServer, RackNerd, VPSDime and Vultr if you sign up through our links. It does not change the price you pay. Every other provider pays us nothing. Prices in this guide are as of the date shown and may have changed; see the comparison pages for the latest checked prices.
Guides · BLOG
How to set up automated backups on any VPS in 2026
Some prices quoted in this guide are out of date. It is being rebuilt on our price index; for current prices use the comparison pages, which show when each price was checked.
Every VPS provider offers a backup add-on at ~20% of your plan price. Those backups live on the same provider — meaning if your provider has an outage or your account gets disabled, the backups are gone too. This guide walks through a real backup setup: restic + Backblaze B2. Encrypted, deduplicated, off-server, and costs under $1/month for typical workloads.
Why not just use the provider's backup add-on?
Provider-managed backups (Hetzner Backup, DO Snapshots, Vultr Backup) are convenient but:
- Same provider. If your account is disabled, backups go with it.
- Same region (usually). A datacenter fire takes both.
- Limited retention (7-14 days typically).
- Whole-VM snapshots, not file-level. Restoring a single file is awkward.
- 20% of plan cost. For a $50 plan, $10/mo — more than off-provider alternatives.
The correct approach: use provider backups as first-line convenience for quick rollbacks, plus off-provider backups for real disaster recovery.
The stack
- restic — encrypted, deduplicated backup tool. Free and open source.
- Backblaze B2 — cheap S3-compatible object storage. $6 per TB per month, first 10 GB free.
- cron — schedule the backup.
Total cost for a small VPS backup (10-50 GB): ~$0-1/mo.
Step 1: Install restic
On Debian/Ubuntu:
```bash
apt update
apt install restic
```
On CentOS/Rocky:
```bash
yum install epel-release
yum install restic
```
Or download the latest binary from github.com/restic/restic/releases.
Step 2: Create a Backblaze B2 bucket
- Sign up at
backblaze.com. - Create an application key with read/write access.
- Create a private bucket for backups (e.g.,
myvps-backups). - Note down: your key ID, application key, and bucket name.
Step 3: Initialise the restic repository
```bash
export B2_ACCOUNT_ID="your-key-id"
export B2_ACCOUNT_KEY="your-application-key"
export RESTIC_REPOSITORY="b2:myvps-backups"
export RESTIC_PASSWORD="a-strong-passphrase-you-will-not-forget"
restic init
```
Write down the passphrase in your password manager. Without it, your backups are unreadable.
Step 4: Run your first backup
```bash
restic backup /var/www /etc/nginx /home
```
restic scans, deduplicates, encrypts, and uploads. First backup takes minutes to hours depending on size.
Verify:
```bash
restic snapshots
restic ls latest
```
Step 5: Automate with cron
Create /etc/backup-env:
```bash
B2_ACCOUNT_ID=your-key-id
B2_ACCOUNT_KEY=your-application-key
RESTIC_REPOSITORY=b2:myvps-backups
RESTIC_PASSWORD=your-passphrase
```
chmod 600 /etc/backup-env — nobody but root should read it.
Create /usr/local/bin/backup-vps:
```bash
#!/bin/bash
set -euo pipefail
source /etc/backup-env
export B2_ACCOUNT_ID B2_ACCOUNT_KEY RESTIC_REPOSITORY RESTIC_PASSWORD
Dump databases to /tmp before backing them up
sudo -u postgres pg_dumpall | gzip > /tmp/postgres-backup.sql.gz
Or MySQL
mysqldump --all-databases | gzip > /tmp/mysql-backup.sql.gz
Backup: files, config, database dumps
restic backup \
/var/www \
/etc/nginx \
/etc/systemd/system \
/home \
/tmp/postgres-backup.sql.gz
Clean up dumps
rm -f /tmp/postgres-backup.sql.gz
Prune old snapshots (keep last 7 daily, 4 weekly, 12 monthly)
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
```
chmod +x /usr/local/bin/backup-vps.
Add cron entry:
```bash
crontab -e
Run daily at 3 AM
0 3 * /usr/local/bin/backup-vps >> /var/log/backup.log 2>&1
```
Step 6: Test restore
Never trust an untested backup. Immediately do a restore drill:
```bash
List available snapshots
restic snapshots
Restore the latest snapshot to a temp directory
mkdir -p /tmp/restore-test
restic restore latest --target /tmp/restore-test
Verify files are there
ls /tmp/restore-test/var/www/
Clean up
rm -rf /tmp/restore-test
```
Repeat this quarterly. A backup you can't restore is not a backup.
Step 7: Monitor the cron
The last thing you want is a backup that silently stopped working three weeks ago.
Simplest: send yourself an email if the cron fails. Add to the backup script:
```bash
At end of script
if [ $? -ne 0 ]; then
mail -s "VPS backup FAILED on $(hostname)" [email protected] < /var/log/backup.log
fi
```
Requires mailutils and a working SMTP setup (Postfix relay or Sendgrid/Mailgun SMTP).
Better: use a monitoring service that pings if the cron fails to run:
- Healthchecks.io — free tier, ping URL from your cron. If no ping in the expected window, alerts you.
Add to your script:
```bash
curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/YOUR-UUID
```
Cost math
For a 20 GB working set + database:
- Initial upload: ~20 GB.
- Daily incremental: ~100 MB new/changed data.
- With deduplication, 30 days retained: ~25 GB stored on B2.
- Cost: 25 GB × $0.006/GB-month = $0.15/mo.
Even for a 200 GB working set with heavy churn:
- ~150 GB stored.
- Cost: $0.90/mo.
What you gain vs the provider's backup add-on
- Off-provider. Survives account disable, provider outage, whole-region outage.
- Encrypted. No provider staff can read your data.
- Deduplicated. Same data isn't stored twice.
- File-level restore. Restore one file, not just a whole VM.
- Configurable retention. 12 months of monthly backups by default.
- Cheaper. Under $1/mo for typical VPS.
Common gotchas
"Bucket already exists" on Backblaze. Bucket names are globally unique. Use a prefix like myuser-myvps-backups.
Backup takes hours. First upload is slow. Subsequent runs are fast (deduplication + incremental).
Passphrase lost. Backups are unrecoverable. Store in your password manager AND in a printed sealed envelope somewhere safe.
Cron doesn't run. Cron mails errors to root. Check /var/log/cron or journalctl -u cron.
Database dump is inconsistent. For Postgres, use pg_dump (consistent) not filesystem copy. For MySQL, use mysqldump --single-transaction on InnoDB.
Related guides
- Shared hosting to plain VPS migration — includes basic backup setup.
- Managed WordPress to VPS + Nginx — sets up backups as part of the migration.
- Best hosting for a Postgres database server — backup strategy for the DB tier.