
A backup only earns its keep after you’ve restored it. This VPS restore drill tutorial walks you through a realistic practice run. You’ll restore onto a staging VPS, verify web + email + SSL, then rehearse a clean DNS cutover and a quick rollback.
Aim for clarity, not heroics. By the end, you’ll know how long a restore really takes. You’ll also see what breaks first and which settings live outside the filesystem.
You’ll finish with a checklist you can run every quarter without rebuilding it from scratch.
What you’ll build in this VPS restore drill tutorial
- A staging VPS that can safely receive restored data without touching production
- A “restore manifest” of items that backups often miss (DNS, rDNS, secrets, schedules)
- A validation routine for web, PHP workers, cron, SMTP, IMAP, and TLS
- A cutover plan using low-TTL DNS and a fast rollback path
This tutorial assumes a Linux VPS running Nginx or Apache. Mail is optional (Postfix/Exim + Dovecot).
Commands target Ubuntu 24.04 LTS and Debian 12/13-style systems. The same approach works on AlmaLinux/Rocky, with small path differences.
Prerequisites and a safety-first plan
Pick the type of drill before you touch anything. For most teams, a staging restore is the default.
It can’t affect live traffic.
- Staging restore: restore data to a separate VPS, validate, document steps. Safest.
- Rollback rehearsal: practice restoring onto the same server (use only if you can take downtime).
- Full failover drill: restore to a standby VPS and switch traffic (DNS or load balancer).
For clean results, build staging to closely match production. Resource gaps can hide real issues or create fake ones.
Example: PHP-FPM max_children may behave differently under pressure on a smaller box.
If you don’t want to maintain the OS and baseline stack yourself, managed VPS hosting can help keep images consistent and restores predictable.
Decide your recovery targets
- RPO (data loss tolerance): e.g., “up to 15 minutes” for ecommerce orders
- RTO (time to restore): e.g., “site back in 60 minutes”
Write those targets down. During the drill, time each phase.
If you miss RTO, the fix is usually sequencing, documentation, or backup format.
It’s rarely “move faster.”
Step 1: Inventory what must be restorable (the restore manifest)
Restore failures tend to repeat. A restore manifest forces you to capture what’s “outside the tarball.”
That includes DNS, credentials, and provider-side settings.
Backups often won’t include these items by default.
Filesystem and app data
- Web roots (common:
/var/www,/home/*/public_html) - Nginx/Apache configs (
/etc/nginx,/etc/apache2) - PHP-FPM pools (
/etc/php/*/fpm/pool.d) - SSL material (
/etc/letsencryptor panel-managed paths) - Mail spools (Postfix:
/var/mail,/var/spool/postfix; Exim:/var/spool/exim) - Crons (
/etc/cron*,/var/spool/cronor user crontabs)
Provider and DNS items people forget
- Domain registrar access and nameserver values
- DNS zone records (A/AAAA, MX, DKIM, SPF, DMARC, CAA)
- Reverse DNS / PTR (mail reputation depends on it)
- Firewall rules (UFW/iptables/CSF) and allowed admin IPs
- Monitoring endpoints, uptime checks, webhook URLs
If your drill includes mail, don’t treat reverse DNS as optional.
Use this companion guide for a quick correctness check: PTR record setup tutorial.
Step 2: Build a staging VPS that mirrors production
Create a new VPS with the same OS family and major version. Match architecture (x86_64 vs ARM), disk type, and roughly the same RAM/CPU.
A staging box that’s “close enough” creates noise. You’ll spend time debugging problems you won’t see in production.
For a drill, you can use a standard HostMyCode VPS and keep it powered on only for the test window.
Baseline hardening (enough to avoid self-inflicted issues)
- Update packages
sudo apt update
sudo apt -y full-upgrade
sudo reboot
- Verify SSH access from your admin IP and store a console access method
If you want an SSH hardening baseline that avoids lockouts, follow: SSH lockdown tutorial.
Do this before you restore anything.
Step 3: Choose your restore method (file-level vs image/snapshot)
Your drill goes smoother when the backup format matches what you’re trying to prove.
- Image/snapshot restore: fastest path to a bootable server. Less flexible if you need to restore only one site.
- File-level restore (rsync/tar/restic/rclone): slower, but portable and precise.
If you already back up with rsync, run the drill as an explicit file restore. That way, the steps are documented.
If you rely on snapshots, still validate services and check for config drift.
Snapshots can bring back old firewall rules, stale packages, or outdated service configs.
Need a solid rsync baseline? This guide pairs well with today’s drill: rsync backup tutorial.
Step 4: Restore into staging without breaking production
Two rules keep staging safe: don’t reuse production IPs, and don’t let staging send mail to the internet until you’re ready.
4.1 Put staging behind a temporary hostname
Create a throwaway DNS record like restoretest.example.com pointing to the staging VPS. Leave production records alone.
4.2 Restore files (example: rsync-based)
Adjust paths to your environment. If production uses /var/www:
# On staging VPS
sudo mkdir -p /restore
# From your backup host (or wherever backups live)
rsync -aHAX --numeric-ids --info=progress2 \
/backups/prod-vps/latest/var-www/ \
root@STAGING_IP:/var/www/
Restore configs and service data in a controlled order:
/etc/nginxor/etc/apache2/etc/php/*/fpm/etc/letsencrypt(if you’re restoring existing certs for testing)- Application env files and secrets (WordPress
wp-config.php, .env files)
4.3 Prevent staging from sending live email
Staging servers “accidentally emailing customers” is a classic drill failure.
For Postfix, set a safe transport that can’t deliver. Or block outbound 25/587 at the firewall.
Quick Postfix safety toggle (staging only):
sudo postconf -e 'default_transport = error'
sudo postconf -e 'relay_transport = error'
sudo systemctl restart postfix
You can still test local message generation and log flow without delivering externally.
Step 5: Fix the three restore breakers (permissions, sockets, and service order)
Most “bad restore” reports aren’t missing data. They come from wrong ownership, stale socket paths, or services starting in the wrong order.
5.1 Ownership and permissions quick checks
# Web roots should be readable by the web server user, writable only where needed
sudo find /var/www -maxdepth 3 -type d -name uploads -print
# Spot odd owners (common after tar/rsync without numeric ids)
sudo find /var/www -maxdepth 3 -type f -not -user www-data -ls | head
If you run multiple users (reseller/shared style), confirm each vhost maps to the right UID/GID.
Avoid “fixing” it by chowning everything to www-data. That can break FTP/SFTP workflows and widen permissions in ways you don’t want.
5.2 PHP-FPM socket paths
If Nginx points at a socket that doesn’t exist, you’ll get 502s.
Check what Nginx expects. Then confirm what PHP-FPM is actually listening on:
sudo nginx -T 2>/dev/null | grep -E 'fastcgi_pass|php.*sock' | head
sudo ss -lpn | grep php-fpm || true
Then validate the pool config path, for example:
ls -la /run/php/
# Typical: /run/php/php8.3-fpm.sock
5.3 Service start order
Bring services up in a predictable sequence. That keeps you from debugging side effects.
sudo systemctl daemon-reload
sudo systemctl restart php8.3-fpm || sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx || sudo systemctl restart apache2
If you hit immediate 500/502 errors, don’t guess. Follow the logs.
This pairs perfectly with restore drills: VPS log analysis tutorial.
Step 6: Validate the restore (web, SSL, cron, and mail) with a repeatable checklist
This is where the drill pays off. You’re hunting for quiet breakage.
Look for pages that load but can’t upload files. Also watch for checkout flows that error or cron jobs that never fire.
6.1 Web health and HTTP status
# Replace with your staging hostname
curl -I https://restoretest.example.com
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://restoretest.example.com/
For WordPress, also test admin login, permalinks, and uploads.
If you use object cache plugins, confirm the cache sockets/ports exist on staging.
6.2 TLS sanity (don’t assume the cert is valid)
If you restored /etc/letsencrypt, confirm the certificate matches the hostname.
Also confirm the chain looks right:
echo | openssl s_client -servername restoretest.example.com -connect restoretest.example.com:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates
If you plan to issue a fresh staging certificate instead, do it now. Your HTTPS checks should reflect reality.
For production-grade HTTPS settings you can port between staging and live, see: TLS hardening tutorial.
6.3 Cron and scheduled tasks
List system crons and per-user crons:
sudo ls -la /etc/cron.*
sudo crontab -l || true
sudo ls -la /var/spool/cron/crontabs 2>/dev/null || true
For WordPress sites that rely on WP-Cron, verify scheduled events actually fire.
Missed cron issues often show up right after restores and migrations: WordPress cron troubleshooting tutorial.
6.4 Mail validation (optional, but common on hosting VPS)
Even with outbound mail blocked, you can still confirm services start cleanly and logs behave.
sudo systemctl status postfix exim4 dovecot 2>/dev/null | sed -n '1,8p'
# Check listening ports (25/465/587/993 depending on your stack)
sudo ss -ltnp | egrep ':(25|465|587|993)\b' || true
If you see queue growth or auth failures during the drill, fix them now while the risk is low.
These two guides are designed for that workflow:
Step 7: Rehearse DNS cutover (low TTL, verification, rollback)
Even if you don’t switch real traffic during the drill, practice the cutover steps. DNS is where “everything looks fine” turns into a real outage.
Common causes include a wrong A record, missing AAAA, stale MX, or a CAA record that blocks certificate issuance.
7.1 Lower TTL ahead of time
For production cutovers, set TTL to 300 seconds (5 minutes) at least a few hours before the change.
During a drill, practice the same sequence using a test hostname. Keep the live zone untouched.
7.2 Verify DNS from multiple resolvers
# Replace with your domain/hostname
DIG_HOST=restoretest.example.com
dig +short $DIG_HOST A @1.1.1.1
dig +short $DIG_HOST A @8.8.8.8
dig +short $DIG_HOST AAAA @1.1.1.1
If your real cutover involves moving a site, keep a structured checklist for propagation and common failure modes. This one is built for hosting moves: DNS cutover checklist tutorial.
7.3 Plan a fast rollback
Rollback usually isn’t “restore again.” It’s “point DNS back” plus “stop writes on the new host.”
In your drill notes, spell out:
- Who can change DNS (account + 2FA access)
- Where the previous IPs are recorded
- What data would be lost on rollback (orders, form submissions)
- How you will freeze writes (maintenance mode, read-only flag, or queue orders)
Step 8: Measure your real restore time and fix the bottlenecks
Time each segment and record it in your runbook:
- Provision staging VPS: ____ minutes
- Transfer backup data: ____ minutes for ____ GB
- Service bring-up + fixes: ____ minutes
- Validation pass: ____ minutes
If transfer time dominates, you likely have a bandwidth issue or a restore-unfriendly backup format.
If bring-up dominates, the usual culprit is missing notes.
Paths, package versions, and control panel specifics are common gaps.
Common bottleneck fixes
- Backup too slow to restore: keep a recent “hot” backup on fast storage, archive older copies offsite
- Config drift: store critical configs in version control (private repo) or a secure secrets manager
- Human-only knowledge: convert tribal steps into a one-page runbook with copy/paste commands
Step 9: Turn your drill into an operations runbook (copy/paste)
Use this as a starting template. Keep it in your internal docs.
Update it after every drill while the details are still fresh.
Restore drill runbook template
- Scope: which sites/services are included (web only, web+mail, reseller accounts)
- RPO/RTO targets: documented numbers
- Backup sources: paths/locations and encryption keys owners
- Staging build: VPS size, OS version, required packages
- Restore steps: exact rsync/tar/restic commands and expected output
- Validation checklist: curl checks, admin login, uploads, cron, mail ports
- DNS plan: TTL change timing, record list, rollback steps
- Post-drill actions: delete staging, rotate any exposed secrets, record timings
Wrap-up: make restores boring
A restore drill should feel routine. After a couple of runs, you stop improvising under pressure.
Instead, you follow a script that works.
If you want a platform that fits restore testing—quick provisioning, predictable networking, and optional admin help—run your drills on a HostMyCode VPS.
Or hand the operational load to managed VPS hosting and keep your team focused on application validation and continuity planning.
Regular restore drills are easier when staging capacity is one click away. HostMyCode gives you an affordable HostMyCode VPS you can spin up for a test window and delete afterward, plus managed VPS hosting if you want help keeping the OS and stack consistent for recoverable restores.
FAQ
How often should you run a restore drill?
Quarterly is a solid baseline in 2026 for most VPS-hosted sites. Run it monthly if you handle payments, high-volume lead capture, or frequent code changes.
Should staging restores use the same domain as production?
No. Use a dedicated test hostname (or hosts-file testing) to avoid cache, cookie, and HSTS surprises. Only reuse the production domain during an actual cutover window.
What’s the most common thing backups miss?
DNS and provider-side settings (PTR/rDNS, firewall rules, and monitoring). A restore drill catches these gaps before they become an outage.
How do you test email safely during a restore drill?
Start services, verify logs, and confirm ports locally, but block outbound delivery (Postfix default_transport=error or firewall egress rules). Then enable external sending only if the drill’s scope requires it.
What should you do with the staging VPS after the drill?
Delete it. If you keep it, rotate any secrets that were restored, remove SSH keys you don’t need, and keep it patched like production.