CresignSys Learn — Lesson 071

Written by

in

Build hosting-restore

We now have:

hosting-create
hosting-list
hosting-info
hosting-health
hosting-repair
hosting-ssl
hosting-backup

The next component completes the backup system:

BACKUP
  ↓
RESTORE

The target command:

sudo hosting-restore example.com BACKUP_ID

For example:

sudo hosting-restore example.com 2026-08-13_160000

1. Restore Is a High-Risk Operation

Unlike:

hosting-info
hosting-health

restore modifies customer data.

Therefore the workflow must be much stricter.

SELECT BACKUP
      ↓
VERIFY BACKUP
      ↓
LOCK SITE
      ↓
CREATE PRE-RESTORE BACKUP
      ↓
RESTORE
      ↓
VERIFY
      ↓
HEALTH CHECK
      ↓
ACTIVE

If anything fails:

RESTORE ERROR
      ↓
ROLLBACK

2. Never Restore Directly Over the Live Site

Avoid:

backup
 ↓
rm -rf public
 ↓
extract

This is dangerous.

If extraction fails halfway:

public/
├── some files restored
├── some files missing
└── site broken

Instead use a temporary restore directory.


3. Safe Restore Architecture

LIVE SITE
   │
   │ remains intact
   ▼
TEMPORARY RESTORE
   │
   ▼
VERIFY
   │
   ▼
ACTIVATE

This is much safer.


4. Example Directory Structure

Current:

/storage/websites/example.com/public

Temporary:

/storage/websites/example.com/.restore/

For example:

.restore/
└── 2026-08-13_160000/

5. Better Temporary Location

For very large websites, temporary restoration can require substantial disk space.

Therefore eventually you may want:

/storage/cresignsys/restore-work/

instead of putting temporary data inside the website.

For the first implementation, choose a dedicated location outside the public document root.


6. Restore States

Use:

id="v4l0q8"
RESTORE_REQUESTED
      ↓
VERIFYING
      ↓
PREPARING
      ↓
RESTORING_FILES
      ↓
RESTORING_DATABASE
      ↓
VERIFYING_SITE
      ↓
HEALTH_CHECK
      ↓
ACTIVE

Failure:

RESTORE_ERROR

7. First Step — Find the Backup

Given:

sudo hosting-restore example.com 2026-08-13_160000

the script constructs:

/backup/cresignsys/example.com/2026-08-13_160000/

Then checks:

files archive
database dump
manifest
checksums

8. Verify Manifest

Read:

manifest.json

Check:

domain
site_id
backup ID
status
files archive
database dump

The backup should say:

status = COMPLETE

If:

status = ERROR

stop immediately.


9. Verify Domain

This is a critical safety check.

Suppose you accidentally execute:

hosting-restore shop.example.com BACKUP_FROM_OTHER_SITE

You must not restore it.

The manifest should contain:

DOMAIN=example.com

and the requested domain must match.


10. Verify Site ID

Also compare:

Current site:
SITE_ID=1027

Backup:
SITE_ID=1027

If they don’t match:

ERROR:
Backup belongs to a different site.

This prevents accidental cross-site restoration.


11. Verify Checksums

Run:

sha256sum -c checksums.sha256

Expected:

files.tar.gz: OK
database.sql.gz: OK

If a checksum fails:

RESTORE STOPPED

Do not continue.


12. Why Checksum Verification Comes Before Restore

Without verification:

corrupted backup
      ↓
restore
      ↓
corrupted website

With verification:

corrupted backup
      ↓
checksum failure
      ↓
restore stopped

13. Acquire Site Lock

Before modifying anything:

/var/lock/cresignsys-example.com.lock

The lock prevents:

hosting-backup
hosting-repair
hosting-delete
hosting-restore

from simultaneously modifying the same site.


14. Create Pre-Restore Backup

This is one of the most important steps.

Before restoring:

CURRENT SITE
     ↓
BACKUP
     ↓
RESTORE OLD BACKUP

If restoration fails:

OLD CURRENT SITE
     ↓
ROLLBACK

Therefore:

Never perform a production restore without preserving the current state.


15. Pre-Restore Backup

You can call:

hosting-backup example.com

from the restore workflow, but ideally the backup engine should be implemented as a reusable internal module rather than invoking a separate command blindly.


16. Maintenance Mode

For database/file replacement, users shouldn’t continue modifying the site.

WordPress maintenance mode can be enabled with WP-CLI:

sudo -u "$SITE_USER" \
wp --path="$WEB_ROOT" maintenance-mode activate

However, if the site is already inaccessible, this may not work.

Therefore maintenance mode is an enhancement, not the primary safety mechanism.


17. Database Restore Is Different From File Restore

Files:

archive
 ↓
extract

Database:

SQL dump
 ↓
MySQL

They need separate verification.


18. Never Drop the Live Database First

A dangerous workflow:

DROP DATABASE
      ↓
CREATE DATABASE
      ↓
IMPORT

If import fails:

database gone

Instead use a safer strategy.


19. Database Restore Strategy

For a first controlled implementation:

current database
       ↓
pre-restore backup
       ↓
prepare restore database
       ↓
import
       ↓
verify
       ↓
activate

There are several ways to implement this depending on your MySQL architecture.


20. Option A — Temporary Database

Example:

Current:
csp1027_wp

Temporary:
csp1027_restore_20260813

Import the dump into:

csp1027_restore_20260813

Then verify it.

This is safer than destroying the current database first.


21. Verify Temporary Database

After import:

temporary database
        ↓
WordPress tables?
        ↓
wp_options?
        ↓
wp_posts?
        ↓
wp_users?

You can query the temporary database to ensure the expected WordPress structure exists.


22. Database Swap

Once the temporary database is verified, the final database transition must be performed carefully.

Depending on your MySQL setup, this may involve:

rename/swap strategy

or:

controlled replacement

The exact mechanism should be tested extensively before production use.


23. Why Not Just Import Into Existing Database?

You could:

mysql existing_database < backup.sql

but this can leave old tables or conflicting schema/data depending on the dump.

For example:

current:
wp_posts
wp_users
wp_options
old_custom_table

backup:
wp_posts
wp_users
wp_options

The old custom table may remain.

A clean restore requires a controlled database replacement strategy.


24. File Restore Strategy

Create:

restore-work/
└── public/

Extract:

files.tar.gz

into the temporary location.

Then verify:

wp-admin/
wp-content/
wp-includes/
wp-config.php

or the site’s expected structure.


25. Don’t Assume Every Site Is WordPress

Your CHP platform is currently WordPress-focused.

But the architecture should eventually support:

WordPress
PHP application
static site
Laravel
custom PHP

Therefore the restore engine should eventually know:

APPLICATION_TYPE=wordpress

rather than assuming WordPress forever.


26. Current WordPress Implementation

For now:

APPLICATION_TYPE=wordpress

can be stored in:

site.conf

Example:

APPLICATION_TYPE=wordpress

Then:

hosting-restore
      ↓
application type
      ↓
WordPress restore verification

27. File Ownership

After restoring files:

chown -R "$SITE_USER:$SITE_USER" "$WEB_ROOT"

But ownership should match the architecture established during provisioning.

Don’t blindly apply ownership rules to unrelated server paths.


28. Permissions

Then restore expected permissions.

Typical baseline:

directories → 755
files       → 644

But special files may require different permissions.

For example:

wp-config.php

may need tighter permissions depending on your PHP-FPM and deployment model.


29. Don’t Run chmod -R 777

Never use:

chmod -R 777

as a restore solution.

It hides permission problems while creating unnecessary security exposure.


30. Verify WordPress

After restoring:

sudo -u "$SITE_USER" \
wp --path="$WEB_ROOT" core is-installed

Then:

sudo -u "$SITE_USER" \
wp --path="$WEB_ROOT" db check

And:

sudo -u "$SITE_USER" \
wp --path="$WEB_ROOT" core verify-checksums

31. Verify Site URL

Check:

sudo -u "$SITE_USER" \
wp --path="$WEB_ROOT" option get siteurl

and:

sudo -u "$SITE_USER" \
wp --path="$WEB_ROOT" option get home

Make sure they match the intended domain/environment.


32. Important Restore Problem

Suppose the backup was created when the site used:

https://example.com

but the current site configuration is:

https://new.example.com

Restoring the old database may restore:

https://example.com

This can create redirects or incorrect URLs.

Therefore restore should preserve the backup’s application state unless the administrator explicitly requests a migration.


33. Restore vs Migration

These are different operations.

Restore

example.com
     ↓
example.com

Migration

old.example.com
     ↓
new.example.com

Don’t mix them.

A future command should be something like:

hosting-migrate old.example.com new.example.com

34. SSL During Restore

The database/files backup doesn’t necessarily mean the certificate should be restored as raw certificate files.

Certificates should remain managed by the SSL subsystem.

After restore:

website restored
       ↓
hosting-ssl status
       ↓
certificate still valid?

If necessary:

hosting-ssl

can repair/reconfigure HTTPS.


35. Nginx Configuration

Similarly, restore should not blindly overwrite the entire server’s Nginx configuration.

Your backup may contain:

site.conf

as metadata, but Nginx configuration should be generated from the current CHP templates.

Therefore:

Backup
 ↓
site metadata
 ↓
current CHP template
 ↓
Nginx configuration

This avoids restoring obsolete server configuration.


36. PHP Configuration

Same principle.

Don’t blindly restore an old:

/etc/php/8.3/fpm/pool.d/

configuration from a backup.

Instead:

site metadata
 ↓
current PHP template
 ↓
current PHP configuration

The backup should restore customer/application data, not necessarily obsolete infrastructure configuration.


37. This Is a Critical Architecture Principle

Separate:

Customer Data

WordPress
uploads
database
themes
plugins

from:

Infrastructure Configuration

Nginx
PHP-FPM
SSL
systemd
firewall
server packages

The restore engine should treat them differently.


38. Restore Architecture

                  BACKUP
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
     Customer Data       Site Metadata
          │                   │
          ▼                   ▼
       Restore            Regenerate
          │              infrastructure
          │                   │
          └─────────┬─────────┘
                    ▼
               HEALTH CHECK

39. Final Health Check

After restoration:

hosting-health example.com

must run.

Expected:

[OK] Web Root
[OK] PHP-FPM
[OK] PHP Socket
[OK] Nginx
[OK] WordPress
[OK] Database
[OK] HTTP
[OK] HTTPS

Only then:

STATUS=ACTIVE

40. Restore Failure

Suppose:

Files        ✓
Database     ✓
WordPress    ✓
HTTP         ✗

Do not mark:

ACTIVE

Instead:

RESTORE_ERROR

Then rollback if appropriate.


41. Rollback

The safest high-level sequence is:

Current site
    ↓
Pre-restore backup
    ↓
Selected backup
    ↓
Restore
    ↓
Health failure
    ↓
Restore pre-restore backup

This creates a recovery chain.


42. Restore State Machine

ACTIVE
  │
  ▼
RESTORE_REQUESTED
  │
  ▼
VERIFYING
  │
  ▼
PRE_RESTORE_BACKUP
  │
  ▼
RESTORING
  │
  ▼
VERIFYING
  │
  ▼
HEALTH_CHECK
  │
 ┌┴──────────┐
 ▼           ▼
PASS        FAIL
 │           │
 ▼           ▼
ACTIVE     ROLLBACK
             │
             ▼
           ACTIVE

If rollback itself fails:

ROLLBACK_ERROR

and immediate administrator intervention is required.


43. Restore Logs

Example:

2026-08-13 17:00 RESTORE_START
2026-08-13 17:00 BACKUP_VERIFIED
2026-08-13 17:01 PRE_RESTORE_BACKUP_COMPLETE
2026-08-13 17:02 FILES_RESTORED
2026-08-13 17:03 DATABASE_RESTORED
2026-08-13 17:03 PERMISSIONS_FIXED
2026-08-13 17:03 WORDPRESS_VERIFIED
2026-08-13 17:04 HEALTH_CHECK
2026-08-13 17:04 RESTORE_COMPLETE

44. Restore Output

A successful restore:

CresignSys Restore
==================

Domain:
example.com

Backup:
2026-08-13_160000

[OK] Backup verified
[OK] Current site backed up
[OK] Files restored
[OK] Database restored
[OK] Ownership verified
[OK] WordPress verified
[OK] Nginx verified
[OK] PHP verified
[OK] Health check

Status:
ACTIVE

45. Failed Restore

CresignSys Restore
==================

Domain:
example.com

[OK] Backup verified
[OK] Current site backed up
[OK] Files restored
[OK] Database restored
[FAIL] WordPress verification

Attempting rollback...

[OK] Previous files restored
[OK] Previous database restored
[OK] Health check

Status:
ACTIVE

This is the kind of behavior you want from a production system.


46. Dry Run

Because restore is dangerous, add:

sudo hosting-restore example.com 2026-08-13_160000 --dry-run

The dry run should show:

Restore Plan
============

Domain:
example.com

Backup:
2026-08-13_160000

Files:
1.4 GB

Database:
28 MB

Actions:
[ ] Create pre-restore backup
[ ] Restore files
[ ] Restore database
[ ] Fix permissions
[ ] Verify WordPress
[ ] Health check

No changes made.

47. Confirmation

For destructive operations, interactive confirmation can provide another safety barrier.

For example:

WARNING:
This operation will replace the current website state.

Current:
2026-08-13 17:00

Restore:
2026-08-10 16:00

Continue? [yes/no]

For automated systems, use an explicit non-interactive approval flag rather than relying on a prompt.


48. Why --force Is Dangerous

Avoid:

hosting-restore example.com BACKUP --force

unless --force has a precisely defined meaning.

Better:

hosting-restore example.com BACKUP --confirm

where the semantics are explicitly:

I understand this operation will modify the live site.

49. Restore Database Credentials

The restored wp-config.php may contain credentials corresponding to the backup environment.

If the current database credentials differ, WordPress may stop working.

Therefore your restore system should decide which configuration is authoritative.

For CHP:

CURRENT INFRASTRUCTURE
        ↓
current DB credentials

should generally remain authoritative.

Customer data is restored separately.


50. Important Separation

Don’t blindly restore:

old wp-config.php

over the current environment if it contains environment-specific configuration.

A safer design is:

backup wp-config.php
        ↓
extract application settings
        ↓
preserve current CHP-managed credentials/configuration

This is another reason to separate application data from infrastructure configuration.


51. WordPress Restore Strategy

A mature CHP restore can therefore do:

Restore:
wp-admin
wp-content
wp-includes
application files
database

Preserve/regenerate:
wp-config.php
Nginx
PHP-FPM
SSL
server configuration

The exact boundary depends on your deployment architecture.


52. Backup Manifest Improvement

Record which components were backed up:

{
  "domain": "example.com",
  "site_id": "1027",
  "application": "wordpress",
  "files": true,
  "database": true,
  "site_metadata": true,
  "nginx_config": false,
  "php_config": false,
  "ssl_private_key": false
}

This prevents ambiguity during restoration.


53. Restore Compatibility

A backup may have been created under:

PHP 8.2

while the current server uses:

PHP 8.3

The restore system should report:

Backup PHP:
8.2

Current PHP:
8.3

rather than silently assuming compatibility.


54. Compatibility Warning

For example:

WARNING:
Backup was created under PHP 8.2.
Current site uses PHP 8.3.

Continue?

This is especially important for old WordPress plugins and custom PHP code.


55. Database Version

Similarly record:

MySQL version

in the backup manifest.

For example:

{
  "mysql_version": "8.0"
}

Then the restore process can identify major compatibility changes.


56. Restore Testing

The best way to test restore is:

Production
    ↓
Backup
    ↓
Temporary environment
    ↓
Restore
    ↓
Health check

This is called a:

Restore Test

You should eventually automate this.


57. Disaster Recovery Testing

A serious hosting platform should periodically test:

Can we actually restore this site?

not simply:

Does a backup file exist?

This distinction is critical.


58. Recovery Point Objective

RPO means approximately:

How much recent data can we afford to lose?

Example:

RPO = 24 hours

means a failure could potentially lose up to a day’s changes.

If:

RPO = 1 hour

you need much more frequent backup/snapshot mechanisms.


59. Recovery Time Objective

RTO means:

How quickly must the site be restored?

Example:

RTO = 4 hours

versus:

RTO = 15 minutes

The second requires much more sophisticated infrastructure.


60. CHP Backup Strategy

Eventually hosting plans could define:

Plan
 │
 ├── Backup frequency
 ├── Retention
 ├── Remote backup
 ├── RPO
 └── RTO

This makes backup a proper hosting service rather than simply a Bash script.


61. Current CHP Recovery Layer

We now have:

                   RECOVERY
                      │
          ┌───────────┴───────────┐
          ▼                       ▼
       Backup                  Restore
          │                       │
          ▼                       ▼
       Verify                  Verify
          │                       │
          └───────────┬───────────┘
                      ▼
                  Health Check
                      │
                      ▼
                   ACTIVE

62. Complete Website Lifecycle

The platform now looks like:

CREATE
  ↓
CONFIGURE
  ↓
SSL
  ↓
ACTIVE
  ↓
HEALTH
  ↓
BACKUP
  ↓
REPAIR
  ↓
RESTORE
  ↓
ACTIVE

63. Current Command Set

hosting-create DOMAIN

hosting-list

hosting-info DOMAIN

hosting-health DOMAIN

hosting-repair DOMAIN --php
hosting-repair DOMAIN --nginx
hosting-repair DOMAIN --permissions
hosting-repair DOMAIN --wordpress

hosting-ssl DOMAIN

hosting-backup DOMAIN

hosting-restore DOMAIN BACKUP_ID

This is becoming a real operational platform.


64. Lesson 071 — Core Principle

The safest restore architecture is:

VERIFY
  ↓
PROTECT CURRENT STATE
  ↓
RESTORE
  ↓
VERIFY
  ↓
HEALTH CHECK
  ↓
ACTIVATE

Never:

DELETE CURRENT DATA
  ↓
HOPE RESTORE WORKS

The key rule is:

A restore operation must have a recovery path of its own.


Next Lesson — 072

Build hosting-backup-list and Retention

We now need to manage multiple backups.

The next commands will be:

sudo hosting-backup-list example.com
sudo hosting-backup-delete example.com BACKUP_ID

and eventually:

sudo hosting-backup-prune example.com

The system will calculate:

Daily backups
Weekly backups
Monthly backups
Retention
Backup size
Oldest backup
Newest backup
Failed backups

and safely remove only backups that are eligible for deletion.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *