Every VPS operator has backups. Very few have ever restored one under pressure. The gap between a backup and a recovery capability is measured in two numbers that most teams never write down: your RTO (recovery time objective — how long until service is back) and RPO (recovery point objective — how much data you can afford to lose). This article builds a disaster recovery plan around those two numbers, then shows how to prove the plan works with real restore drills rather than optimism. If you are still selecting a provider, it helps to compare VPS hosting plans on backup and snapshot capability specifically.
Start With RTO and RPO, Not With Tooling
Backups are a means; recovery targets are the end. Before choosing a tool, answer two questions:
- RTO: If the VPS died now, how many minutes of downtime is acceptable? One hour? Fifteen minutes?
- RPO: How much data can you lose? A day of writes? An hour? Zero?
These numbers drive everything. An RPO of a day permits daily snapshots. An RPO of fifteen minutes forces streaming replication or continuous WAL shipping. Teams that skip this step buy tooling that does not meet their actual recovery need — or overspend on continuous replication for data they could rebuild from source.
The 3-2-1 Rule Applied to a VPS
The 3-2-1 rule still holds: three copies, two media types, one offsite. For a VPS this translates directly:
- Copy 1 (primary): live data on the VPS
- Copy 2 (local/off-instance): provider snapshots or a separate attached volume
- Copy 3 (offsite): encrypted backups pushed to object storage
The critical detail most plans omit: a snapshot stored inside the same provider account is not truly offsite. If the account is compromised or a billing failure suspends the whole account, both the instance and its snapshots disappear together. Push copy 3 to a genuinely separate provider or object-storage bucket with independent credentials.
Encryption, Retention, and Incrementals
Your backup tooling must encrypt in transit and at rest. Restic and BorgBackup both handle this cleanly with client-side encryption, so the storage provider never sees plaintext. A minimal restic workflow:
export RESTIC_REPOSITORY=s3:s3.amazonaws.com/example-backups
export RESTIC_PASSWORD_FILE=/root/.restic-pw
restic init
restic backup /etc /var/www /var/lib/mysql --exclude-caches
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
The forget --prune policy gives you a week of dailies, a month of weeklies, and six months of monthlies — enough to survive both accidental deletion and slow-rolling corruption. Incremental backups keep transfer volume low; both tools deduplicate, so a second daily run moves only changed blocks.
The Restore Drill: The Only Test That Counts
A backup you have never restored is a hypothesis. The drill is a scripted procedure run on a schedule, ideally monthly, restoring into an isolated instance and asserting that the data is intact and the service starts. A restic drill:
restic snapshots --latest 5
restic restore latest --target /mnt/dr-test
cat /mnt/dr-test/etc/hostname
mysql --execute='CHECK TABLE wp_posts' < /dev/null
curl -sS -o /dev/null -w '%{http_code}\n' https://dr-test.example.com/
Time the whole drill. The wall-clock duration is your actual RTO, and it is almost always longer than the number in your plan document. Repeat until measured RTO approaches the target, or adjust the target to reality. The discipline of verifying checksums before a restore is the same principle covered in verifying backup integrity with checksums — you want corruption to surface during a drill, not during an incident.
Automate the Verification, Not Just the Backup
Backups that fail silently are the norm, not the exception. Automate two checks: a repository integrity check after each run, and a periodic restore drill. Wire both into a systemd timer so a failure pages you:
restic check --read-data-subset=5%
# exit non-zero on failure -> alert via your monitoring
--read-data-subset=5% re-reads and verifies a random 5% of pack files each run, which catches bit-rot across the whole repository over weeks without re-downloading everything. This is the automated equivalent of your monthly manual drill and is described in more depth in automated backup verification and restore drills.
Document the Runbook
The final piece is a written runbook that a stressed-out engineer can follow at 3 a.m. It should contain the exact restore commands, the storage credentials' location (never the credentials themselves), the DNS cutover steps, and the verification checks. Test that a second person can execute it without your help — that is the real test of a DR plan, and it is the one that fails most often.
Failure Modes You Must Design For
Backups fail in predictable ways, and a mature plan names each one. The four that bite most teams:
- Silent backup job failure. The cron entry runs, the tool exits non-zero, and nobody reads the mail. Mitigation: an alert on non-zero exit and a monitored "last successful backup" timestamp.
- Credentials rotation. Storage keys rotate, the backup script keeps an old key, and every run fails quietly. Mitigation: store secrets in one place and test the backup path after each rotation.
- Account suspension. Snapshots living in the same provider account vanish with the instance. Mitigation: genuinely separate offsite storage.
- Slow-rolling corruption. The database was subtly broken three weeks ago; today's backup faithfully preserves the corruption. Mitigation: retention long enough to reach a pre-corruption restore point plus periodic data-integrity assertions.
Database-Consistent Backups
Copying MySQL data files while the server is writing produces a torn, unusable backup. Use a logical dump with consistent read semantics, or coordinate a filesystem snapshot with a flush. The straightforward and reliable approach:
mysqldump --single-transaction --routines --triggers \
--all-databases | gzip | restic backup --stdin --stdin-filename dump.sql.gz
--single-transaction takes a consistent InnoDB snapshot without locking tables, so the application keeps serving during the dump. Streaming straight into restic avoids a full-size temp file on disk — important on a small VPS where a multi-gigabyte dump could fill the volume and abort the job. The same consistency discipline matters for point-in-time restore; if you run replication, the mechanics are covered in setting up MySQL master-slave replication on a VPS.
The Takeaway
Disaster recovery is a measured capability, not a checkbox. Define RTO and RPO first, implement a genuinely offsite 3-2-1 backup with client-side encryption, and prove it with timed restore drills that a colleague can run unaided. Automate integrity checks so silent failures surface early. Do that, and a server failure becomes a scheduled procedure instead of an outage.




Leave a Reply
You must be logged in to post a comment.