Back to tutorials
Tutorial

VPS Restore Drill Tutorial (2026): Prove Your Backups Work with a Full Rebuild and DNS Cutover on Ubuntu

VPS restore drill tutorial for 2026: rebuild Ubuntu, restore data, validate SSL, and cut over DNS with minimal downtime.

By Anurag Singh
Updated on Jun 16, 2026
Category: Tutorial
Share article
VPS Restore Drill Tutorial (2026): Prove Your Backups Work with a Full Rebuild and DNS Cutover on Ubuntu

A backup you’ve never restored is a comforting idea, not an operational plan. This VPS restore drill tutorial walks you through a full rebuild on Ubuntu. You’ll restore files and config, verify TLS and email paths, then cut over DNS without guesswork.

You’re not aiming for perfect infrastructure-as-code. You’re building a repeatable drill you can run quarterly (and before risky upgrades). The goal is to learn your real recovery time and find the first things that fail.

What you’ll build in this VPS restore drill tutorial

  • A clean recovery VPS (staging/standby) with the same OS major version as production
  • Restored web content, app config, and secrets (without copying garbage)
  • Verified services: Nginx/Apache, PHP-FPM (if used), cron, and TLS
  • A controlled DNS cutover plan using low TTL and rollback
  • A written “RTO reality check” (your actual restore time)

Assumptions: Ubuntu Server 24.04 LTS or 22.04 LTS, SSH access, and backups already exist (snapshots, rsync, object storage, etc.). If you’re still building backup automation, treat this restore drill as the acceptance test.

Your backup process should pass this drill every time.

Prerequisites: a realistic recovery target

Test on a VPS that resembles production. If prod is 2 vCPU / 4 GB RAM with NVMe, don’t run the drill on a tiny instance and call it “validated.”

Underpowered tests hide the real pain. They can mask timeouts, swap thrash, and slow decompression.

  • Pick a standby VPS: same region (or your planned DR region) with similar specs
  • Use the same OS major version: upgrading mid-restore creates brand-new failure modes
  • Keep it isolated: don’t aim production DNS at it until the cutover step

If you want a disposable standby box for drills, a HostMyCode VPS gives you a clean Ubuntu baseline you can rebuild quickly, then delete after the test.

If you want someone to run the drill, validate services, and document the runbook, managed VPS hosting is the better fit.

Step 1: Record your current server “fingerprint” (10 minutes)

Before you touch the standby VPS, capture a few facts from production. You’ll use them later to confirm the restore matches reality.

# On production
hostnamectl
lsb_release -a || cat /etc/os-release
uname -r

# Web stack and runtime versions
nginx -v 2>&1 || true
apache2 -v 2>&1 || httpd -v 2>&1 || true
php -v 2>&1 || true
php-fpm8.3 -v 2>&1 || php-fpm8.2 -v 2>&1 || true
mysql --version 2>&1 || mariadb --version 2>&1 || true

# Open ports snapshot
ss -tulpn | sed -n '1,200p'

# Disk and mount points
df -hT
lsblk -f

Next, list your hosted sites and their document roots (or app directories). On Nginx, vhosts usually live in /etc/nginx/sites-available/. They’re enabled via sites-enabled.

On Apache for Ubuntu, check /etc/apache2/sites-available/.

Step 2: Build the standby VPS and lock down access

Provision a fresh Ubuntu VPS. Apply your baseline security: SSH keys, a non-root sudo user, and a firewall that starts tight.

If your SSH setup varies between servers, use your internal standard. Or use this reference: SSH key setup tutorial.

# On the standby VPS
sudo apt update
sudo apt -y install ufw

# Allow SSH first, then enable
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose

Keep inbound rules minimal during the restore. Add 80/443 later, right before validation and cutover.

Step 3: Restore the OS-level packages you actually need (not everything)

The most common restore anti-pattern is “install until it stops erroring.” That can produce a working server, but nobody knows why it works.

Use the drill to make dependencies explicit.

On production, export a package list as a starting point. On Ubuntu, this captures manually installed packages:

# On production (captures manually installed packages)
apt-mark showmanual > /root/apt-manual.txt

Copy the list to the standby VPS, then install selectively. Don’t replay years of leftovers.

Start with the core services and tools you’ll need during recovery:

# On standby
sudo apt update

# Choose one web server path (example: Nginx + PHP-FPM)
sudo apt -y install nginx
sudo apt -y install php-fpm php-cli php-mysql php-curl php-xml php-mbstring php-zip

# Helpful tools for restore and debugging
sudo apt -y install rsync tar unzip jq curl ca-certificates

If you’re on Apache, install apache2 and the modules your sites require.

For multi-site Apache setups, keep this guide nearby for the validation step: Apache virtual hosts tutorial.

Step 4: Restore web files and configs safely (rsync approach)

A reliable restore order is simple. Restore configs first, then web roots, then secrets. After that, reload services.

If you reverse the order, you’ll debug “failures” that are really missing config.

Pick your source:

  • If you have an offsite file backup (object storage / remote server), restore from there.
  • If you’re restoring from a snapshot mounted somewhere, copy from the mounted snapshot.

Example restore layout to target:

  • Nginx config: /etc/nginx/
  • Apache config: /etc/apache2/
  • Web roots: /var/www/ (or your custom path)
  • Let’s Encrypt: /etc/letsencrypt/ (only if you know what you’re doing; often better to re-issue)
# Example: restoring from a remote backup server over SSH
# Run from standby VPS
export BACKUP_HOST="backup.example.com"

# Restore Nginx configs
sudo rsync -aHAX --numeric-ids --delete \
  "${BACKUP_HOST}:/backups/prod/etc/nginx/" \
  /etc/nginx/

# Restore web roots
sudo rsync -aHAX --numeric-ids --delete \
  "${BACKUP_HOST}:/backups/prod/var/www/" \
  /var/www/

Why these flags? -aHAX preserves permissions, hardlinks, ACLs, and xattrs where applicable. --numeric-ids avoids UID/GID surprises when user IDs differ between servers.

Even with these flags, plan to review ownership after the copy.

Step 5: Fix ownership and permissions (the part that always breaks)

Most “restore failures” are permission failures. They show up as 403s, caches that won’t write, and uploads that silently fail.

Don’t chase web server bugs until you verify ownership.

First confirm the web user:

# Ubuntu typically uses www-data
id www-data

Then apply a predictable ownership model per site. Example for a PHP/WordPress site in /var/www/example.com:

sudo chown -R www-data:www-data /var/www/example.com

# Conservative directory/file perms
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo find /var/www/example.com -type f -exec chmod 644 {} \;

If you run multiple sites with per-site system users, don’t flatten everything to www-data. Restore each vhost user/group first.

Then apply ownership per site so you don’t weaken isolation.

Step 6: Restore application secrets and environment files

Good backups often exclude secrets. That’s the right default.

It can still bite you during a restore under pressure. Your drill should prove you know where secrets live and how to put them back.

  • WordPress: wp-config.php (DB creds, salts)
  • Laravel/Symfony: .env or runtime secrets store
  • Custom apps: systemd unit overrides in /etc/systemd/system/*.service.d/

For a drill, temporary credentials and a staging database are fine. What matters is a documented process.

Write down where secrets come from, how you rotate them, and who can access them.

Step 7: Bring up services and validate locally before opening the firewall

Start services and validate configs. Only then make the server reachable from the internet.

This keeps early mistakes private.

# Nginx example
sudo nginx -t
sudo systemctl enable --now nginx
sudo systemctl status nginx --no-pager

# PHP-FPM (version may differ)
sudo systemctl enable --now php8.3-fpm || sudo systemctl enable --now php8.2-fpm

Test via a hosts-file override from your laptop. This lets you hit the standby server without changing DNS.

Add a temporary entry mapping your domain to the standby IP:

# On your laptop (example)
203.0.113.50  example.com www.example.com

Then hit it and check the response headers:

curl -I http://example.com

Step 8: TLS/SSL: decide whether to restore certificates or re-issue

In most drills, re-issuing certificates is cleaner than copying /etc/letsencrypt between servers. It avoids stale renewal state, missing account keys, and mismatched permissions.

If you want a straightforward Nginx + Let’s Encrypt setup, follow: SSL certificate setup guide.

Typical standby issuance flow (after allowing 80/443):

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo apt -y install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

If you terminate TLS upstream (HAProxy, etc.), validate termination config and backend health.

This reference pairs well: TLS termination setup guide.

Step 9: Validate the restore with a tight checklist

“Homepage loads” isn’t a validation plan. Test what users actually touch: logins, uploads, scheduled tasks, and anything that sends email.

  • HTTP status: 200/301 expected, no loops
  • PHP: no fatal errors in logs
  • Static assets: CSS/JS loads (no missing permissions)
  • Uploads/write paths: media upload works
  • Background jobs: cron or systemd timers run
  • Email send path: contact forms deliver (or relay works)

Quick log checks:

# Nginx logs
sudo tail -n 80 /var/log/nginx/error.log
sudo tail -n 80 /var/log/nginx/access.log

# PHP-FPM logs (paths vary)
sudo journalctl -u php8.3-fpm -n 80 --no-pager || true
sudo journalctl -u php8.2-fpm -n 80 --no-pager || true

Step 10: DNS cutover with low TTL and a rollback plan

The safest cutover is intentionally boring. Lower TTL ahead of time. Keep the old server running.

Switch A/AAAA records, then verify from multiple places.

If you need a refresher on low-TTL cutovers, use your internal process or this guide: DNS failover setup guide tutorial.

  1. 24 hours before: lower TTL for the relevant records (e.g., 300 seconds). Some DNS providers enforce minimums; capture that in your runbook.
  2. Right before cutover: confirm the standby serves the correct content over HTTPS and has the needed firewall rules.
  3. Switch: update A/AAAA for example.com and www to the standby IPs.
  4. Verify from multiple networks: home, mobile, and a remote resolver.
  5. Rollback: if errors spike, revert records to the old IP immediately and keep troubleshooting off the public path.

Commands to confirm DNS propagation:

# Replace with your domain
DOMAIN=example.com

# Query public resolvers
dig +short A $DOMAIN @1.1.1.1
dig +short A $DOMAIN @8.8.8.8

# Check effective TTL and record details
dig A $DOMAIN @1.1.1.1

Step 11: Measure your real RTO and write the runbook

Time the drill end-to-end. Don’t estimate. Put the number in writing.

  • Start time: moment you can’t use production
  • Restore complete: site works on standby via hosts-file
  • Public recovery: DNS cutover finished and SSL verified

Then write a one-page runbook that includes:

  • Exact backup locations and credentials ownership (who can access them)
  • Commands you used (copy/paste ready)
  • Which config files must exist (vhosts, PHP-FPM pools, cron, systemd units)
  • Where secrets come from
  • Rollback steps and decision point (“if X fails for Y minutes, roll back”)

Common restore drill failures (and fast fixes)

  • SSH locked out after firewall enable: keep an active session while enabling UFW; allow SSH first. If you break it, use your provider console or recovery mode. For triage steps, see firewall troubleshooting tutorial.
  • 404s on assets after restore: vhost root points to a path that doesn’t exist on standby; check root in Nginx or DocumentRoot in Apache.
  • 502 Bad Gateway: PHP-FPM socket path differs (e.g., /run/php/php8.3-fpm.sock vs 8.2); update the Nginx upstream and reload.
  • Permissions broken: restore preserved old UIDs; fix ownership with chown and consider standardizing user IDs across servers.
  • Disk fills during restore: decompression + logs + old cache directories; clear app caches and confirm free space early. This diagnostic guide helps: disk space troubleshooting tutorial.

Operational checklist you can reuse (print this)

  • Standby VPS created (same Ubuntu major, similar resources)
  • SSH keys + sudo user + firewall applied
  • Core packages installed (web server, PHP runtime, utilities)
  • Configs restored and validated (nginx -t / apachectl configtest)
  • Web roots restored; permissions verified
  • Secrets injected; app boots without manual guessing
  • HTTPS working (re-issue or restored certs intentionally)
  • Functional tests passed (login, upload, cron, email)
  • DNS TTL lowered; cutover done; rollback tested on paper
  • RTO measured and recorded; runbook updated

Summary: make restore drills part of normal hosting operations

Restore drills turn “we think we’re backed up” into a recovery time you can plan around. After the first run, the second goes faster.

The mystery is gone. You’ve pinned down exact paths, versions, and service dependencies.

If you want a clean environment to test restores without risking production, start with a HostMyCode VPS.

If you’d rather hand off the rebuild and validation (including a practical cutover plan),

If your business can’t afford a “we’ll figure it out during the outage” restore, schedule a quarterly restore drill on a standby server. HostMyCode makes it easy to spin up a recovery target with a HostMyCode VPS, or you can have our team run the drill end-to-end and deliver a copy/paste runbook through managed VPS hosting.

FAQ

How often should you run a VPS restore drill in 2026?

Quarterly is a solid baseline for most sites. Run it after major stack changes (PHP version bumps, web server swaps, new control panel) or before peak season.

Should you restore SSL certificates from backup or re-issue them?

Re-issuing is usually safer and faster. Restore certificates only if you have a specific reason (pinned cert workflows, offline issuance, or strict change controls) and you understand the renewal state.

What’s the fastest way to reduce DNS downtime during cutover?

Lower TTL ahead of time (often 300 seconds), keep the old server up during propagation, and verify from multiple resolvers. Always have a rollback IP ready.

What’s the most common reason a restore “works” but the site is broken?

File ownership and runtime mismatches. A restored site can load the homepage while uploads, cache writes, background jobs, or PHP-FPM sockets fail silently until you test them.

Can you run a restore drill without changing public DNS?

Yes. Use a hosts-file override or a temporary subdomain like drill.example.com pointing to the standby VPS. You still want at least one real cutover test occasionally to validate your DNS process.

VPS Restore Drill Tutorial (2026): Prove Your Backups Work with a Full Rebuild and DNS Cutover on Ubuntu | HostMyCode