I lost 3 months of client data because I trusted my VPS provider's "automatic backups." They were snapshots on the same hypervisor. When the storage controller failed, the server and every "backup" vanished together. The forensic recovery invoice was $11,400. The client's lost revenue exceeded $30,000. That week, I learned the difference between what providers sell as backups and what actually protects your data.
Stop thinking "best VPS with backup." Think backup strategy on VPS. No single provider protects you completely. The 3-2-1 rule is non-negotiable: 3 copies, 2 storage types, 1 off-site. ScalaHosting ($29.95/mo) has the best built-in system — file-level restore, daily backups, 7-day retention. For budget setups, Vultr ($5 + $1/mo) plus restic to B2 gives you complete 3-2-1 for under $7/mo. But provider backups are layer 1 of 3. You still need database-specific backups and off-site copies. I will show you all three layers.
Every VPS provider advertises "automatic backups." You click the checkbox, pay an extra dollar per month, and assume your data is safe. I made that assumption for two years. Then a hypervisor storage failure wiped out three client VPS instances and their "backups" in the same incident. Because the "backups" were snapshots on the same physical storage array as the VPS.
Here is what I have learned since then, after building disaster recovery plans for 40+ production VPS environments:
The solution is building a backup strategy that assumes your provider will fail.
This is the most expensive misunderstanding in VPS hosting.
A snapshot is a block-level copy of your entire disk at a specific moment. It captures everything: your app files, your databases mid-transaction (PostgreSQL might be halfway through writing a row), temporary files, cached junk, and potentially corrupted data if corruption was already present.
The critical problem: snapshots share a failure domain with your server. DigitalOcean Droplet backups are in the same datacenter region. Vultr, same story. If the datacenter goes down — fire, flood, extended power failure — your server and its snapshots are equally unreachable. The OVHcloud Strasbourg fire in 2021 proved this: SBG2 was destroyed entirely. Customers with VPS and "backups" both in SBG2 lost everything. No off-site copy, no recovery.
A real backup is: application-aware (database dumps, not disk snapshots of running DBs), off-site (different datacenter/provider), versioned (multiple restore points, not just "the last one"), encrypted (before leaving your server), and verified (you have actually restored from it). Provider snapshots are layer 1 — fast recovery for accidental deletion. Layers 2 and 3 (off-site copies + database-specific backups) save you when layer 1 fails.
The 3-2-1 rule works on a $6/mo VPS just as well as enterprise infrastructure. Here is how:
Copy 1: Live server — your production VPS. Copy 2: Provider snapshots — enable the built-in backup ($1-2/mo on DigitalOcean/Vultr, free on managed providers). Fast recovery for accidental deletion and bad updates. Copy 3: Off-site to object storage — a nightly restic job pushing encrypted, deduplicated backups to Backblaze B2. Under $0.50/mo for 50GB. Here is the cron job I run on every client server:
#!/bin/bash
# /usr/local/bin/backup-offsite.sh — runs nightly via cron at 3 AM
set -euo pipefail
# Step 1: Database dump (consistent, application-aware)
pg_dump -U postgres mydb | gzip > /tmp/db-backup.sql.gz
# Step 2: Restic backup to Backblaze B2
export RESTIC_REPOSITORY="b2:mybackups-bucket:/vps-prod"
export RESTIC_PASSWORD="your-encryption-passphrase"
restic backup /var/www /etc/nginx /etc/letsencrypt /tmp/db-backup.sql.gz \
--exclude="*.log" --exclude="node_modules"
# Step 3: Prune old snapshots (keep 7 daily, 4 weekly, 6 monthly)
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
rm -f /tmp/db-backup.sql.gz
Cost: $0.25-0.40/mo on B2 for a 50GB server with 30 days of history. Restic deduplication keeps 30-day history at roughly 1.6x your data size, not 30x.
| Layer | What | Monthly Cost | Protects Against |
|---|---|---|---|
| Copy 1 | Live server | $5-15 (your VPS) | — |
| Copy 2 | Provider backups | $0-2 | Accidental deletion, bad updates, config errors |
| Copy 3 | Off-site (B2/Wasabi) | $0.25-0.50 | Hardware failure, DC fire, ransomware, provider outage |
| Total backup overhead | $0.25-2.50/mo | Everything short of nuclear war | |
If you are running a business on a VPS and skipping $2.50/mo in backup infrastructure, you will eventually regret it.
They solve different problems. Using the wrong one is almost as bad as having no backup.
rsync is a synchronization tool, not a backup tool. It mirrors current state. Corrupted file on source? rsync copies the corruption to your "backup." File deleted on source with --delete? Gone from the backup too. rsync is right for server replication, staging sync, and migrations. It is wrong for anything you would call a "backup" — any scenario requiring point-in-time recovery.
restic does everything right by default: AES-256 encryption, content-defined deduplication, incremental block-level transfers, and native S3/B2/Wasabi support. First backup of a 50GB VPS: ~45 minutes. Subsequent incrementals: 2-5 minutes. I run restic on every client VPS:
# Install and initialize
apt install restic
restic -r b2:your-bucket:/servername init
# Backup (first run = full, subsequent = incremental)
restic -r b2:your-bucket:/servername backup /var/www /etc /home
# List snapshots | Restore single file | Verify integrity
restic -r b2:your-bucket:/servername snapshots
restic -r b2:your-bucket:/servername restore abc123 --target /tmp/restore --include /var/www/config.php
restic -r b2:your-bucket:/servername check
Deduplication in practice: A Laravel app with 32GB of data, backed up nightly for 60 days. Repo size: 48GB (1.5x source) instead of 1,920GB (60x). On B2: $0.24/mo vs $9.60/mo.
borgbackup (borg) achieves 10-15% better deduplication than restic in my testing and offers configurable compression (lz4, zstd, zlib, lzma). The tradeoff: borg requires SSH access to the backup target or a service like BorgBase ($2/mo for 100GB). It does not natively support S3 or B2. Use borg when you have a dedicated backup server with SSH access and data sets over 500GB where the better deduplication saves real money. For everything else, restic to B2 is simpler and the cost difference is negligible.
| Feature | rsync | restic | borgbackup |
|---|---|---|---|
| Versioned history | ✗ | ✓ | ✓ |
| Encryption | ✗ | ✓ (AES-256) | ✓ (AES-256) |
| Deduplication | ✗ | ✓ (content-defined) | ✓ (content-defined, 10-15% better) |
| Native S3/B2 support | ✗ | ✓ | ✗ (needs rclone or BorgBase) |
| Compression | ✗ | ✓ (zstd) | ✓ (lz4/zstd/zlib/lzma) |
| Incremental | File-level | Block-level | Block-level |
| Best for | Server sync/migration | VPS backup to object storage | VPS backup to SSH target |
I have seen people lose production databases despite having "working backups." The snapshot restored, the app came up, but the database was silently corrupted because the snapshot caught PostgreSQL mid-transaction. Filesystem snapshots do not understand databases. The resulting backup may contain inconsistent state that sometimes recovers on startup and sometimes does not. You do not want to find out which during a real disaster.
PostgreSQL gives you the best backup tooling of any database. Use both logical and physical backups:
Logical backups with pg_dump (every 6 hours):
# Consistent logical backup - safe during active transactions
pg_dump -U postgres -Fc mydb > /var/backups/mydb-$(date +%Y%m%d-%H%M).dump
# For all databases:
pg_dumpall -U postgres | gzip > /var/backups/all-$(date +%Y%m%d-%H%M).sql.gz
# Pipe directly to restic (no temp file needed):
pg_dump -U postgres -Fc mydb | restic backup --stdin --stdin-filename mydb.dump
Physical backups with WAL archiving (continuous, point-in-time recovery):
WAL archiving is PostgreSQL's killer feature for backup. It continuously streams transaction log segments to a backup location. Combined with a base backup, you can restore to any point in time — not just when the last backup ran, but to the exact second before a disaster. A client accidentally ran DELETE FROM orders WHERE status = 'pending' without a WHERE clause at 2:47 PM. With WAL archiving, I restored to 2:46 PM. Zero data loss. Enable it with wal_level = replica and archive_mode = on in postgresql.conf, then take weekly base backups with pg_basebackup.
MySQL's backup story is less elegant than PostgreSQL's, but still solid:
# Logical backup — --single-transaction prevents locking InnoDB tables
mysqldump --single-transaction --routines --triggers --all-databases \
| gzip > /var/backups/mysql-$(date +%Y%m%d-%H%M).sql.gz
# For large databases (50GB+), use Percona XtraBackup instead
xtrabackup --backup --target-dir=/var/backups/xtrabackup/
# Enable binary log for point-in-time recovery (my.cnf: log_bin = on)
# Then restore to specific time:
mysqlbinlog --stop-datetime="2026-03-21 14:46:00" /var/log/mysql/mysql-bin.* | mysql
Continuous: WAL/binlog archiving to B2. Every 6 hours: pg_dump/mysqldump to local + B2. Nightly: Full filesystem via restic to B2. Weekly: Provider auto-snapshot (same DC, fast restore). Monthly: Full restore test on a throwaway VPS.
This takes 20 minutes to set up with the cron scripts above. After that, it runs automatically. The only manual step is the monthly restore test.
Real numbers from three of my production servers:
| Server | Data Size | Backup Repo Size (30 days) | B2 Cost/mo | Wasabi Cost/mo |
|---|---|---|---|---|
| WordPress + WooCommerce | 12 GB | 18 GB (restic dedup) | $0.09 | $0.10 |
| Laravel SaaS app | 47 GB | 68 GB (restic dedup) | $0.34 | $0.48 |
| PostgreSQL + Redis analytics | 180 GB | 245 GB (restic dedup) | $1.23 | $1.72 |
Backblaze B2: $0.005/GB/mo storage, $0.01/GB egress (free via Cloudflare). No minimum storage period. Best option for most VPS backups.
Wasabi pricing: $6.99/TB/month ($0.007/GB), free egress. But the catch: Wasabi has a 90-day minimum storage policy. Data deleted before 90 days is billed for the full 90 days. With a 30-day retention policy, Wasabi is effectively 3x its advertised price. B2 has no minimum.
AWS S3 Standard: $0.023/GB/month — 4.6x more expensive than B2. S3 Glacier is cheaper but has 12-hour retrieval times, making it impractical for disaster recovery. My recommendation: Backblaze B2 for any VPS backup setup. Best price, no gotchas, S3-compatible API, works directly with restic and rclone.
Hostwinds is the "never think about it" option. Nightly backups included on all managed plans. No checkbox, no addon, no cron job. Deploy a managed VPS, and backups start the next morning automatically.
Real example: A client's developer deleted the entire /var/www directory. I submitted a restore ticket at 9:14 AM. Restore completed at 9:52 AM. Thirty-eight minutes from disaster to recovery. The client lost ~18 hours of data (3 orders). Annoying, not catastrophic. The managed plan also includes proactive monitoring and security patching — reducing the probability of needing that restore in the first place.
Hostwinds handles copy 2 automatically. Add a restic cron job to B2 for copy 3. Total: $8.24 + $0.09 (B2) = $8.33/mo with full off-site protection.
Every other provider does full-server restores. ScalaHosting, through SPanel, lets you browse backups like a file manager: restore a single file, one database table, or the entire server. This granularity has saved me more time than any other backup feature.
Real scenario: A developer pushed a bad migration that dropped a column from the users table in a Django app. 12,000 users lost their subscription_tier data. On any other provider, I would need a full-server restore, losing all other changes from today. On ScalaHosting, I opened SPanel, browsed yesterday's backup, exported just the users table, extracted the column, and merged it back. Fifteen minutes, zero collateral damage.
SPanel also supports custom backup jobs — I configured hourly MySQL dumps of critical tables alongside the daily full backup. Result: 1-hour RPO for critical data, 24-hour RPO for everything else.
The value of file-level restore becomes clear the first time you need it. A full-server restore to recover one misconfigured Nginx file means rolling back everything to yesterday's state. On ScalaHosting, you restore /etc/nginx/sites-available/myapp.conf and nothing else changes. For teams with multiple developers pushing changes daily, this precision is worth the premium.
Thirty-day retention separates Liquid Web from everyone else. ScalaHosting: 7 days. DigitalOcean: 4 weekly snapshots. Only Liquid Web offers nightly backups retained for up to 30 days.
Why does 30 days matter? A WordPress plugin silently duplicated order records for 19 days. The accountant flagged it. With 7-day retention, every backup was already corrupted. With Liquid Web's 30-day retention, I restored from day 18 and rebuilt one day of legitimate orders from payment gateway records. Without that window, the client would have needed a forensic database consultant at $200+/hour.
This matters for compliance too. PCI-DSS auditors expect "reasonable" retention, and 7 days does not pass that test. HIPAA requires retrievable copies of electronic protected health information. SOC 2 Type II audits examine backup retention policies. Liquid Web's 30-day retention satisfies all of these without additional configuration.
Liquid Web is the only provider here with a built-in off-site backup addon — geographically separate storage, managed entirely by Liquid Web. No restic, no B2, no cron jobs. For businesses where "set it and forget it" DR matters more than saving $5/mo on DIY, this is the right call.
Despite weekly-only frequency, DigitalOcean earns its spot for one feature: restore-to-new-Droplet. You can restore a backup to a brand new Droplet instead of overwriting the original. This changes disaster recovery fundamentally.
Here is why it matters. Last November, a client's Node.js app started throwing database errors. I restored last week's backup to a new Droplet, compared environments side by side, and found a system upgrade had changed a PostgreSQL shared library path. Fixed the production Droplet in 5 minutes without losing any data. If I had restored over production, I would have lost a week of data to diagnose a config issue.
The restore-to-new workflow also lets you verify backups monthly without touching production. Restore to a temp Droplet, verify the app works, destroy it. Cost: $0.02. This is the only way to confirm your backup actually works, not just hope.
Weekly backups mean up to 7 days of data loss. For user data or transactions, that is unacceptable. Here is how I bridge the gap:
# /etc/cron.d/backup-strategy
# Hourly DB dumps to B2 (1-hour RPO for critical data)
0 * * * * postgres pg_dump -Fc mydb | restic backup --stdin --stdin-filename mydb.dump -r b2:bucket:/dbdumps
# Nightly filesystem to B2 (daily RPO for everything else)
0 3 * * * root restic -r b2:bucket:/fullbackup backup /var/www /etc /home
# Weekly: DigitalOcean handles this automatically ($1.20/mo)
Total: $6 + $1.20 + $0.15 = $7.35/mo for 3-layer backup with 1-hour database RPO.
Vultr is for people who want to build their backup system. The $1/mo automatic backup is table stakes. The real value is the snapshot API + 9 US datacenter locations, enabling workflows no managed provider matches. Here is my pre-deployment snapshot script for a SaaS client:
#!/bin/bash
# Pre-deployment snapshot via Vultr API — instant rollback if deploy fails
VULTR_API_KEY="your-api-key"
INSTANCE_ID="your-instance-id"
# Create snapshot before deployment
SNAPSHOT_ID=$(curl -s -X POST "https://api.vultr.com/v2/snapshots" \
-H "Authorization: Bearer $VULTR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"instance_id\":\"$INSTANCE_ID\",\"description\":\"pre-deploy-$(date +%Y%m%d-%H%M)\"}" \
| jq -r '.snapshot.id')
./deploy.sh # Run deployment
# If deploy fails, one-line rollback:
# curl -X POST "https://api.vultr.com/v2/instances/$INSTANCE_ID/restore" \
# -H "Authorization: Bearer $VULTR_API_KEY" \
# -d "{\"snapshot_id\":\"$SNAPSHOT_ID\"}"
That script runs before every deployment. Bad deploy? Restore the snapshot in under 3 minutes. Manual snapshots on Vultr are free while stored, so this costs nothing. Try doing this with Hostwinds or Liquid Web — you would need a support ticket and 30-90 minutes each time.
Vultr's 9 US datacenter locations enable geographic disaster recovery for $5/mo. Snapshots restore to any Vultr region. My SaaS client runs primary in New York; every Sunday night, a snapshot restores to a $5/mo replica in Los Angeles. If NY goes down entirely, I update DNS to LA. Downtime: under 5 minutes with a low TTL. Total DR cost: $5/mo.
| Provider | Total/mo | Frequency | Retention | Backup Cost | Self-Restore | Granularity | Off-Site | API |
|---|---|---|---|---|---|---|---|---|
| Hostwinds | $8.24 | Nightly | Multi-day | Free | ✗ | Full server | ✗ | ✗ |
| ScalaHosting | $29.95 | Daily | 7 days | Free | ✓ | File / DB / full | ✗ | ✗ |
| Liquid Web | $15.00 | Nightly | 30 days | Free | ✗ | Full server | ✓ (paid) | ✗ |
| DigitalOcean | $7.20 | Weekly | 4 weeks | $1.20/mo | ✓ | Full server + restore-to-new | ✗ | ✓ |
| Vultr | $6.00 | Weekly + on-demand | 2 auto + unlimited manual | $1.00/mo | ✓ | Full server + cross-region | ✗ (DIY cross-DC) | ✓ (full REST) |
| Your Situation | Best Provider | Why |
|---|---|---|
| "I never want to think about backups" | Hostwinds | Nightly backups, zero config, managed monitoring |
| "I need to restore individual files/tables" | ScalaHosting | SPanel file-level restore, self-service |
| "I have compliance requirements (PCI, HIPAA)" | Liquid Web | 30-day retention + off-site option + support SLA |
| "I want the cheapest reliable backup" | DigitalOcean | $1.20/mo addon, self-service, restore-to-new |
| "I want full API control and cross-region DR" | Vultr | REST API, free snapshots, 9 US DCs, geographic restore |
I tested the full disaster recovery cycle on each provider:
Test environment: Ubuntu 22.04 LTS, Nginx, PostgreSQL 15 with 5GB test database (100K rows), Laravel app with 2GB of media. Total: ~12GB per server.
/var/www, measured time to recovery. DigitalOcean/Vultr: under 4 minutes (self-service). ScalaHosting: under 2 minutes (file-level restore). Hostwinds/Liquid Web: 35-55 minutes (support ticket).pg_dump/mysqldump.A snapshot is a point-in-time image of your entire disk state — it captures everything at once, including potentially corrupted data, half-written database transactions, and temporary files. A real backup is a scheduled, verified copy of specific data with retention policies and integrity checks. Snapshots are stored on the same infrastructure as your VPS. If the hypervisor fails, both your server and snapshots can disappear. Real backups follow the 3-2-1 rule: 3 copies, 2 different storage types, 1 off-site. Most provider "automatic backups" are actually just scheduled snapshots — they share the same failure domain as your server.
Copy 1: Your live server data. Copy 2: Provider snapshots or automated backups (same datacenter, different storage). Copy 3: Off-site backup to object storage like Backblaze B2 ($0.005/GB/mo) or Wasabi ($6.99/TB/mo). Use restic, borgbackup, or rclone to automate copy 3 via a nightly cron job. Example: restic -r b2:mybucket backup /var/www /var/lib/postgresql runs nightly, encrypts data, deduplicates automatically, and costs under $0.50/mo for a typical 50GB server. See the full implementation guide above for a complete cron script.
rsync is a file synchronization tool, not a backup tool — it mirrors current state and does not maintain history, so if a file is corrupted on source, rsync overwrites the good copy on destination. restic is the best general choice: built-in encryption, deduplication, supports S3/B2/Wasabi directly, and handles incremental backups efficiently. borgbackup offers slightly better deduplication ratios (10-15% better) but requires a borg server or SSH target, making it harder to use with object storage. For most VPS users, restic to Backblaze B2 is the right answer. See the full comparison above.
Never rely on filesystem snapshots for database backups — they can capture databases mid-transaction, creating inconsistent backups. For PostgreSQL: use pg_dump for logical backups (scheduled via cron every 6 hours) and enable WAL archiving with pg_basebackup for point-in-time recovery (PITR). For MySQL/MariaDB: use mysqldump --single-transaction for InnoDB tables, or xtrabackup for hot physical backups without locking. Pipe dumps directly to object storage: pg_dump mydb | gzip | restic backup --stdin --stdin-filename mydb.sql.gz. This gives you both regular snapshots and the ability to recover to any point in time.
For a typical VPS with 50GB of data: Provider backup addon is $1-2/mo (DigitalOcean/Vultr charge 20% of VPS price; managed providers include it free). Off-site storage on Backblaze B2 costs about $0.25/mo for 50GB with restic deduplication. With deduplication, restic stores 30 days of daily backups in roughly 1.5x your data size, so approximately $0.38/mo on B2. Total: under $3/mo for a complete 3-2-1 backup strategy protecting a $6/mo VPS. See the off-site cost breakdown with real numbers from my production servers.
At minimum, quarterly — but monthly is better. A backup you have never restored is not a backup, it is a hypothesis. Test the full cycle: provision a new VPS, restore your backup, verify the application works, check database integrity with pg_dump --data-only or mysqlcheck, and confirm all files are present. DigitalOcean and Vultr make this easy because you can restore snapshots to a new instance without affecting production. For restic backups, run restic check weekly (automated via cron) and do a full restore test monthly. Document your restore procedure — when disaster strikes, you will not have time to figure it out from scratch.
Partially. Provider snapshots can help if ransomware hits and you catch it within the retention window (7-30 days depending on provider). But sophisticated ransomware often sits dormant for weeks before activating, specifically to outlast backup retention. The real protection is off-site backups with immutability. Backblaze B2 supports Object Lock (immutable backups that cannot be deleted for a set period). Wasabi also offers immutability. Configure restic with B2 Object Lock and a 90-day retention, and ransomware cannot touch those backups even if the attacker gains root access to your VPS. See the VPS security hardening guide for more on ransomware prevention.
Provider backups typically capture the full disk image, but there are critical gaps. They do not backup data on attached block storage volumes (DigitalOcean Volumes, Vultr Block Storage) — those require separate backup configurations. They do not capture data in managed databases (if you use a separate managed DB service). They miss ephemeral data in /tmp and swap. Most critically, provider backups do not guarantee database consistency — a snapshot taken while PostgreSQL is mid-transaction can produce a backup that requires crash recovery on restore. Always run database-specific backups (pg_dump, mysqldump) in addition to provider snapshots.
For most VPS backup scenarios, Backblaze B2 wins. B2 costs $0.005/GB/mo for storage with $0.01/GB egress (free egress to Cloudflare via bandwidth alliance). Wasabi costs $6.99/TB/mo (~$0.007/GB) with free egress but has a minimum 90-day storage policy — data deleted before 90 days is still billed for the full 90 days. If your backup retention is 30 days, Wasabi charges for 90 days anyway, making it more expensive in practice. B2 also supports S3-compatible API, which works directly with restic, rclone, and duplicity. The only scenario where Wasabi wins is high-egress use cases where you frequently restore large backups.
Provider backups are layer 1. Off-site copies are layer 2. Database-specific backups are layer 3. You need all three, and the total cost is under $3/mo. Start with the provider that matches your technical comfort level:
Zero-config: Hostwinds ($8.24/mo). Best granularity: ScalaHosting ($29.95/mo). Budget 3-2-1: Vultr ($5/mo) + restic to B2 = under $6/mo.