WordPress Single-Site Recovery Runbook
Use this page when one WordPress site is broken but the server and other sites are still healthy.
Purpose
This process restores one WordPress site at a time. It is for plugin failures, theme failures, bad updates, accidental content deletion, or a compromise limited to one site.
Important: this is not the full server disaster recovery process. For primary server failure, use the Server DR runbook.
Site Structure
Each WordPress site should be isolated under its own domain directory:
/var/www/<domain>/ public/ WordPress files logs/ site-specific logs backups/ site-specific backups tmp/ temporary files
Each site should also have its own Linux user, PHP-FPM pool, MariaDB database, and MariaDB user.
Result: restoring site-a.com should not roll back site-b.com or any other site.
When To Use This
- One WordPress site breaks after a plugin, theme, or core update.
- Pages, posts, uploads, or settings are deleted by mistake.
- One site shows signs of compromise but the server remains stable.
- Only one site's database or files need to be rolled back.
Do Not Use This For
- Primary server hardware failure.
- Operating system failure.
- MariaDB corruption affecting all databases.
- nginx or PHP-FPM failure affecting every site.
Use the Server DR runbook for those cases.
Information Needed Before Restore
- Domain:
example.com - Site path:
/var/www/example.com/public - Database name:
example_wp - Backup snapshot timestamp:
YYYYMMDD-HHMMSS - Per-database dump path:
/mnt/backup-usb/database/per-database/YYYYMMDD-HHMMSS/example_wp.sql.gz - Reason for restore and current symptoms.
Recovery Procedure
- Confirm the problem is limited to one site.
- Record the current time, domain, symptoms, and selected backup timestamp.
- If possible, put only the broken site into maintenance mode.
- Take a just-before-restore copy of the current broken files and database.
- Restore that site's
public/directory from the selected backup snapshot. - Restore only that site's MariaDB database from the matching database dump.
- Confirm file ownership and permissions match the site user.
- Reload PHP-FPM/nginx only if configuration or permissions require it.
- Test the public site,
/wp-admin/, login, media uploads, forms, and any business-critical workflow. - Remove maintenance mode after validation.
Command Template
Use this as a step-by-step template. Replace the example values first, then run one step at a time. Stop if any verification command fails.
Step 1: Set The Site Details
Change these four values to match the broken WordPress site and the backup snapshot you want to restore.
DOMAIN="example.com" DB_NAME="example_wp" SITE_USER="example" SNAPSHOT="YYYYMMDD-HHMMSS"
Step 2: Build The Paths
These paths are based on the values above. The backup path points to the files saved by the USB backup job.
SITE_ROOT="/var/www/${DOMAIN}"
WEB_ROOT="${SITE_ROOT}/public"
BACKUP_ROOT="/mnt/backup-usb/snapshots/${SNAPSHOT}/files/var/www/${DOMAIN}"
DB_BACKUP="/mnt/backup-usb/database/per-database/${SNAPSHOT}/${DB_NAME}.sql.gz"
Step 3: Verify Before Changing Anything
Confirm the live site path, backup files, and database dump exist before running any restore command.
sudo test -d "$WEB_ROOT" && echo "OK: current site path exists" sudo test -d "$BACKUP_ROOT/public" && echo "OK: backup site files exist" sudo test -f "$DB_BACKUP" && echo "OK: database backup exists"
Step 4: Save The Current Broken State
This gives you a local rollback point in case the selected backup snapshot is wrong.
sudo mkdir -p "${SITE_ROOT}/backups/pre-restore-${SNAPSHOT}"
sudo rsync -a --delete "$WEB_ROOT/" "${SITE_ROOT}/backups/pre-restore-${SNAPSHOT}/public/"
sudo mysqldump "$DB_NAME" | sudo gzip -c > "${SITE_ROOT}/backups/pre-restore-${SNAPSHOT}/${DB_NAME}.sql.gz"
Step 5: Restore The Site Files
This replaces only this site's WordPress files with the files from the selected backup snapshot.
sudo rsync -a --delete "$BACKUP_ROOT/public/" "$WEB_ROOT/"
sudo chown -R "${SITE_USER}:${SITE_USER}" "$WEB_ROOT"
Risk: rsync --delete removes live files that are not present in the selected backup. Confirm DOMAIN and SNAPSHOT before running this step.
Step 6: Restore The Site Database
This imports only this WordPress site's database. It does not restore every database on the server.
sudo gzip -dc "$DB_BACKUP" | sudo mysql "$DB_NAME"
Risk: restoring the database rolls this WordPress site back to the selected backup time.
Verification Commands
systemctl is-active mariadb php8.3-fpm nginx curl -I https://example.com/ curl -I https://example.com/wp-admin/ sudo -u example wp core version --path=/var/www/example.com/public sudo -u example wp plugin list --path=/var/www/example.com/public sudo -u example wp theme list --path=/var/www/example.com/public
Also check the site manually in a browser: homepage, admin login, media library, forms, search, checkout, or other important pages.
Rollback If Restore Is Wrong
If the selected backup snapshot is wrong, restore from the safety copy made before the restore:
DOMAIN="example.com"
DB_NAME="example_wp"
SITE_USER="example"
RESTORE_TAG="pre-restore-YYYYMMDD-HHMMSS"
SITE_ROOT="/var/www/${DOMAIN}"
WEB_ROOT="${SITE_ROOT}/public"
sudo rsync -a --delete "${SITE_ROOT}/backups/${RESTORE_TAG}/public/" "$WEB_ROOT/"
sudo chown -R "${SITE_USER}:${SITE_USER}" "$WEB_ROOT"
sudo gzip -dc "${SITE_ROOT}/backups/${RESTORE_TAG}/${DB_NAME}.sql.gz" | sudo mysql "$DB_NAME"
Owner Explanation
Each WordPress site is treated as a separate recoverable unit. If one site breaks, we restore only that site's files and database. Other WordPress sites on the server continue running and are not rolled back.
Full server disaster recovery is only for a larger outage, such as hardware failure or a failed primary server.
Last updated: 2026-05-13