DEV Community

Peon Sh
Peon Sh

Posted on Originally published at peon.sh

A Backup Strategy for Self-Hosted Apps That Actually Works

The 3-2-1 rule adapted for VPS workloads: what to back up, where to store it, how often, and the restore tests that make it real.

Classify first: most of your server needs no backup
The most useful backup decision is deciding what not to back up. On a container host, three tiers exist. Recreatable: the OS, Docker, images and containers, never back these up; they redeploy from Git and platform configuration in minutes. Configuration: compose definitions, environment variables, proxy state, cheap to back up, tedious to reconstruct; your platform and Git already hold most of it. Irreplaceable: databases and user uploads, this small tier is what backup strategy is actually about, and clarity here means backing up gigabytes instead of the whole disk.

3-2-1, adapted for a VPS budget
The classic rule, three copies, two media, one offsite, maps cleanly onto cheap infrastructure:

Copy 1: the live data on the server
Copy 2: provider snapshots (typically ~20% of instance cost), coarse but gives fast whole-machine restore after catastrophic failure
Copy 3 (the essential one): application-level dumps shipped to object storage at a different provider, Cloudflare R2 or Backblaze B2 run about half a cent per GB-month with free or cheap egress
Different provider matters: it protects against account-level failures (billing lockout, provider incident), which same-provider snapshots do not
Schedules and retention that match how loss happens
Data loss is discovered late: the bad migration from Tuesday surfaces Friday; the corrupted records from March surface in June. Retention must reach back further than your discovery delay. The standard that works: nightly database dumps keeping 7 dailies, 4 weeklies, 6 monthlies, 17 archives per database, covering both "restore yesterday" and "what did this look like last quarter" with bounded storage.

Uploads in object storage are best protected with versioning plus replication to a second bucket, rather than snapshot-style copies. In Peon, database backups are configuration: schedule, retention counts and S3 destination per database, with dumps, uploads and pruning automated and restore as a dashboard action.

Protect the backups themselves

  • Write-only credentials on the server where supported: a compromised host must not be able to delete its own history

  • Bucket versioning as the second line against overwrites and deletions

  • Alert on absence: a backup job that silently stopped is the failure mode that hurts; alert when a backup fails OR when none succeeded in 24 hours, and be suspicious of archives dramatically smaller than yesterday’s

The restore drill is the backup
Nobody needs backups; everybody needs restores, and an untested backup is a hope. Quarterly: pull the newest dump, restore into a scratch database, run a sanity query against production counts, and time the whole procedure with the steps written down. The timing is your real recovery objective, and the drill surfaces every silent failure (expired credentials, format drift, missing tooling) while it is still a calendar item instead of an outage. Teams that drill restore in 20 calm minutes; teams that do not, improvise at 3 a.m.

createdb restore_drill
pg_restore -d restore_drill --no-owner latest.dump
psql restore_drill -c "SELECT count(*) FROM users;" # compare with prod
# write down: minutes taken, surprises found

Top comments (0)