CresignSys Learn — Lesson 087

Written by

in

Build the CHP Backup & Restore Engine

The repair system now depends on one critical capability:

Before CHP changes a website, it must be able to restore the previous state.

Therefore backup is not merely a customer feature.

It is also a safety mechanism for CHP itself.


1. Backup Architecture

We will build:

hosting-backup
hosting-restore
hosting-backup-list
hosting-backup-verify

The flow becomes:

                    WEBSITE
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
        FILES        MYSQL        CONFIG
          │            │            │
          └────────────┼────────────┘
                       ▼
                    MANIFEST
                       │
                       ▼
                   CHECKSUMS
                       │
                       ▼
                VERIFIED BACKUP

2. Create Backup Command

sudo nano /usr/local/bin/hosting-backup

Usage:

sudo hosting-backup example.com

Optional:

sudo hosting-backup example.com --full
sudo hosting-backup example.com --config-only
sudo hosting-backup example.com --json

For the first implementation, focus on a full site backup.


3. What a Full Backup Contains

A full backup should contain:

Website files
MySQL database
Nginx site configuration
Backup manifest
Checksums
Metadata

Conceptually:

BACKUP
├── files/
├── database/
├── config/
├── manifest.json
└── checksums.sha256

4. Backup Directory

Use:

/var/lib/cresignsys/backups/

Structure:

/var/lib/cresignsys/backups/
└── example.com/
    └── BK-20260813-170001/
        ├── files/
        ├── database/
        ├── config/
        ├── manifest.json
        └── checksums.sha256

5. Never Use a Predictable Temporary Directory

Don’t build backups directly in:

/tmp/example.com-backup

with a predictable name.

Use a unique working directory:

/var/lib/cresignsys/tmp/

with a generated identifier.


6. Backup ID

Every backup gets a unique ID:

BK-20260813-170001

or preferably:

BK-20260813-170001-a8f3

The ID becomes the permanent reference.

Example:

sudo hosting-restore example.com BK-20260813-170001-a8f3

7. Backup Database Table

Create:

CREATE TABLE backups (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    site_id INTEGER NOT NULL,
    backup_code TEXT NOT NULL UNIQUE,
    backup_type TEXT NOT NULL,
    storage_path TEXT NOT NULL,
    status TEXT NOT NULL,
    size_bytes INTEGER,
    created_at TEXT NOT NULL,
    verified_at TEXT,
    expires_at TEXT,
    FOREIGN KEY (site_id)
        REFERENCES sites(id)
        ON DELETE CASCADE
);

8. Backup States

Use:

CREATING
CREATED
VERIFYING
VERIFIED
FAILED
RESTORING
RESTORED
CORRUPTED
EXPIRED
DELETED

The important distinction is:

CREATED

does not necessarily mean:

VERIFIED

9. Backup Lifecycle

CREATING
   ↓
CREATED
   ↓
VERIFYING
   ↓
VERIFIED

Failure:

CREATING
   ↓
FAILED

or:

VERIFIED
   ↓
CORRUPTED

if a later integrity check fails.


10. Acquire Site Lock

Backup must use the same site lock:

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

Why?

Because you don’t want:

BACKUP
   +
REPAIR

changing the same files simultaneously.


11. Backup and Repair

Correct:

REPAIR
 ↓
lock
 ↓
backup
 ↓
change

Incorrect:

backup
repair
both running simultaneously

The lock serializes site-changing operations.


12. Database Consistency

A website backup contains two major states:

FILES
DATABASE

These should represent approximately the same application state.

For WordPress:

wp-content/
wp-config.php

and:

MySQL database

must correspond.


13. Why Files Alone Are Not Enough

If you restore only:

wp-content/

but not the database, you may have:

old files
new database

or:

new files
old database

which can produce inconsistent application state.


14. Why Database Alone Is Not Enough

A WordPress database does not contain:

themes
plugins
uploads
wp-config.php

Therefore a real WordPress backup requires both.


15. Database Backup

For MySQL:

mysqldump

should create:

database/example.com.sql

Use credentials securely.

Do not put the database password directly into:

ps
command history
logs

16. Avoid Passwords on the Command Line

Don’t use:

mysqldump -u root -pPASSWORD

because command-line arguments may be visible to other processes or shell history.

Use an appropriate protected MySQL configuration or credential mechanism.


17. Backup Database Name

Retrieve the WordPress database name from the site’s configuration.

For example:

DB_NAME

But don’t expose:

DB_PASSWORD

in the backup manifest.


18. Database Dump

Conceptually:

mysqldump \
    --single-transaction \
    --routines \
    --triggers \
    "$DB_NAME" \
    > "$BACKUP_DIR/database/database.sql"

For InnoDB-heavy WordPress databases, --single-transaction helps create a consistent logical dump without taking a full table lock.


19. Verify Database Dump

After creation:

test -s "$DATABASE_DUMP"

Then:

Database backup:
CREATED

A zero-byte dump must be treated as failure.


20. Database Dump Integrity

At minimum:

mysql --execute="..." 

or a suitable validation process should confirm the dump is structurally usable.

A future version can perform a test import into a temporary database.


21. Files Backup

The site root might be:

/storage/websites/example.com/public

Archive it:

files/site.tar.zst

or:

files/site.tar.gz

For modern Linux systems, tar with compression is appropriate.


22. Example

tar \
    --create \
    --gzip \
    --file="$BACKUP_DIR/files/site.tar.gz" \
    -C "$WEB_ROOT" \
    .

This stores the contents of the site root rather than embedding the entire absolute path.


23. Why -C Matters

Instead of:

/storage/websites/example.com/public/wp-content

inside the archive, you get:

wp-content/

This makes restore safer and more portable.


24. Don’t Archive the Backup Directory

Never put:

/var/lib/cresignsys/backups/

inside the website backup if it resides under the site root.

Otherwise:

backup
 → includes backup
 → includes backup
 → includes backup

could occur.

Keep backup storage outside website roots.


25. Nginx Configuration

Store:

config/nginx.conf

for the specific site.

For example:

/etc/nginx/sites-enabled/example.com.conf

Copy it to:

config/nginx-example.com.conf

26. Preserve Metadata

Record:

owner
group
permissions

for configuration files.

Example:

root:root
0644

27. SSL Metadata

Don’t initially copy private keys into a customer backup unless your security model explicitly supports encrypted key storage.

Instead record:

certificate subject
issuer
expiry
SANs
certificate fingerprint

in the manifest.


28. Why Not Automatically Copy Private Keys?

TLS private keys are highly sensitive.

A backup containing:

privkey.pem

must have significantly stronger security controls.

For the first CHP backup engine:

SSL:
metadata only

is safer.


29. Backup Manifest

Create:

manifest.json

Example:

{
  "backup_code": "BK-20260813-170001-a8f3",
  "domain": "example.com",
  "site_id": 7,
  "backup_type": "FULL",
  "created_at": "2026-08-13T17:00:01+05:30",
  "application": "WORDPRESS",
  "web_root": "/storage/websites/example.com/public",
  "database": "example_wp",
  "files_archive": "files/site.tar.gz",
  "database_dump": "database/database.sql",
  "nginx_config": "config/nginx-example.com.conf"
}

30. Don’t Put Secrets in the Manifest

Never include:

DB_PASSWORD
API_TOKEN
SSH_PRIVATE_KEY
TLS_PRIVATE_KEY

The manifest should describe the backup, not contain credentials.


31. Add Version

Include:

{
  "format_version": 1
}

This is important.

Future CHP versions may change the backup format.


32. Example Future

Today:

format_version:
1

Later:

format_version:
2

The restore engine can determine how to interpret the backup.


33. Checksums

After all backup files are created:

sha256sum

Generate:

checksums.sha256

Example:

abc123...  files/site.tar.gz
def456...  database/database.sql
789abc...  config/nginx-example.com.conf

34. Why SHA-256?

It allows CHP to detect:

corruption
partial copy
unexpected modification

before restoration.


35. Verify the Backup

Run:

sha256sum --check checksums.sha256

Expected:

files/site.tar.gz: OK
database/database.sql: OK
config/nginx-example.com.conf: OK

Then:

Backup:
VERIFIED

36. Backup Verification

The process is:

Create files
     ↓
Create database dump
     ↓
Create config backup
     ↓
Create manifest
     ↓
Generate checksums
     ↓
Verify checksums
     ↓
Mark VERIFIED

37. Backup Size

Calculate:

du -sb "$BACKUP_DIR"

Store:

size_bytes

in the database.

This allows the dashboard to show:

Backup size:
1.8 GB

38. Backup List Command

Create:

sudo nano /usr/local/bin/hosting-backup-list

Usage:

sudo hosting-backup-list example.com

Output:

CresignSys Backups
==================

Site:
example.com

ID                         DATE                 SIZE      STATUS
BK-20260813-170001-a8f3    2026-08-13 17:00     1.8 GB    VERIFIED
BK-20260812-170001-c2a7    2026-08-12 17:00     1.7 GB    VERIFIED
BK-20260811-170001-91fd    2026-08-11 17:00     1.7 GB    VERIFIED

39. Backup Verify Command

Create:

sudo nano /usr/local/bin/hosting-backup-verify

Usage:

sudo hosting-backup-verify example.com BK-20260813-170001-a8f3

It should:

load manifest
 ↓
check required files
 ↓
verify SHA-256
 ↓
validate database dump
 ↓
report result

40. Backup Verification Result

CresignSys Backup Verification
==============================

Backup:
BK-20260813-170001-a8f3

Manifest:
OK

Files archive:
OK

Database dump:
OK

Nginx configuration:
OK

Checksums:
OK

Overall:
VERIFIED

41. Restore Command

Create:

sudo nano /usr/local/bin/hosting-restore

Usage:

sudo hosting-restore example.com BK-20260813-170001-a8f3

But this must be extremely cautious.

Restore is potentially destructive.


42. Restore Should Require Explicit Confirmation

Don’t allow:

hosting-restore example.com BACKUP

to immediately overwrite a production site.

Use:

hosting-restore example.com BACKUP --confirm

or an equivalent explicit confirmation mechanism.


43. Even Better: Restore Plan

Eventually:

hosting-restore-plan
        ↓
review
        ↓
approve
        ↓
hosting-restore

This is safer for production.

For the first implementation, at minimum require an explicit confirmation flag.


44. Restore Workflow

LOAD BACKUP
     ↓
VERIFY BACKUP
     ↓
ACQUIRE LOCK
     ↓
CURRENT SITE BACKUP
     ↓
STOP/QUIESCE IF REQUIRED
     ↓
RESTORE DATABASE
     ↓
RESTORE FILES
     ↓
RESTORE CONFIG
     ↓
VALIDATE
     ↓
HEALTH CHECK
     ↓
RECONCILE

45. Never Restore Without a Safety Backup

Suppose the operator wants:

BK-20260810

restored.

Before doing that, CHP should create:

PRE-RESTORE-20260813

of the current state.

Therefore:

CURRENT
   ↓
SAFETY BACKUP
   ↓
RESTORE OLD BACKUP

If the restore fails:

SAFETY BACKUP
   ↓
ROLLBACK

46. Restore Is Therefore a Transaction

Conceptually:

CURRENT STATE
     │
     ▼
SAFETY BACKUP
     │
     ▼
RESTORE TARGET
     │
     ▼
VALIDATE
     │
 ┌───┴────┐
 ▼        ▼
PASS     FAIL
 │         │
 ▼         ▼
DONE     RESTORE
          SAFETY
          BACKUP

47. Database Restore

For MySQL:

mysql "$DB_NAME" < database/database.sql

But this can be destructive.

Before restoring:

current database
       ↓
temporary safety backup

must exist.


48. Don’t Blindly Drop Production Database

Avoid automatically executing:

DROP DATABASE ...

in the first restore implementation.

A safer first version can restore into a controlled temporary database and validate before switching, or require a stronger manual workflow for destructive replacement.


49. WordPress Restore Complexity

A WordPress restore involves:

FILES
DATABASE
CONFIG

and potentially:

CACHE
PHP VERSION
DOMAIN
SSL

Restoring only files and database does not necessarily restore the entire runtime environment.

Therefore the manifest should record the environment.


50. Environment Metadata

Add:

{
  "environment": {
    "php_version": "8.3",
    "web_server": "nginx",
    "database_engine": "mysql",
    "database_version": "8.0"
  }
}

This helps CHP determine compatibility during restore.


51. Restore Compatibility Check

Before restore:

Backup PHP:
8.3

Current PHP:
8.2

The system should warn:

WARNING

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

Restore may not be compatible.

Don’t silently continue.


52. Backup Manifest Should Record CHP Version

Add:

{
  "chp_version": "1.0",
  "backup_format_version": 1
}

This makes future migration easier.


53. Backup Integrity vs Backup Usability

A checksum tells you:

"The file hasn't changed."

It does not prove:

"The backup can successfully restore a working website."

These are different.


54. Three Backup Levels

Use:

INTEGRITY

means:

checksums valid
STRUCTURAL

means:

archive/database dump can be opened
RESTORABLE

means:

successfully restored and validated

55. Backup Verification Model

Created
  ↓
Integrity verified
  ↓
Structure verified
  ↓
Restore tested
  ↓
RESTORABLE

The first CHP version can initially support:

INTEGRITY
STRUCTURAL

and later implement automated restore testing.


56. Restore Testing

For production-quality hosting:

backup
  ↓
temporary environment
  ↓
restore
  ↓
health check
  ↓
destroy temporary environment

This proves the backup is actually usable.


57. Don’t Test by Destroying Production

Never test a backup with:

restore → production

unless an actual restoration is intended.

Use:

staging
temporary VM
isolated container

for restoration testing.


58. Retention Policy

Backups should eventually follow a policy.

Example:

Daily:
7 copies

Weekly:
4 copies

Monthly:
12 copies

But don’t delete the only remaining backup.


59. Retention Engine

A future command:

hosting-backup-prune example.com

will determine:

which backups are protected
which are expired
which can be deleted

60. Never Delete an Unverified Backup Automatically

Suppose:

Backup A:
VERIFIED

Backup B:
FAILED

Backup C:
VERIFIED

Retention should not treat them identically.

A failed backup should be handled separately.


61. Backup Storage Capacity

The backup system itself needs monitoring.

Check:

df -h /var/lib/cresignsys/backups

If backup storage is full:

BACKUP:
BLOCKED

Do not partially create a backup and report success.


62. Partial Backup Cleanup

If backup creation fails:

creating
 ↓
failure

the incomplete directory should be marked:

FAILED

and cleaned up or quarantined.

Never present it as:

VERIFIED

63. Backup Locking

The backup command should acquire the site lock before:

database dump
file archive
config copy

and release it afterward.

Use:

trap cleanup EXIT

to guarantee cleanup.


64. Database and Files Consistency

For busy WordPress sites, files can change during backup.

For example:

12:00
database dump starts

12:01
new upload occurs

12:02
files archive starts

The backup may contain:

database:
before upload

files:
after upload

This is a subtle consistency problem.


65. First Version Policy

For the first CHP version:

Best-effort application-consistent backup

is acceptable.

But record:

backup consistency:
BEST_EFFORT

in the manifest.

Don’t claim:

ATOMIC

unless you actually guarantee it.


66. Future Consistent Backup

A mature system could:

enable maintenance mode
       ↓
flush application state
       ↓
database snapshot/dump
       ↓
files snapshot
       ↓
disable maintenance mode

or use storage/database snapshot mechanisms.

That is a later feature.


67. Repair Backup vs Customer Backup

This distinction is important.

Customer backup

Long-term:

daily
weekly
monthly

Repair safety backup

Short-term:

before repair

Example:

RP-000021

The repair backup may only need to be retained for:

7–30 days

depending on policy.


68. Backup Types

Use:

FULL
DATABASE
FILES
CONFIG
REPAIR
PRE_RESTORE

Example:

BK-20260813-170001:
FULL

and:

BK-20260813-170500:
REPAIR

69. Repair Backup Relationship

Add:

ALTER TABLE backups
ADD COLUMN source_operation_id INTEGER;

Then:

REPAIR
  ↓
BACKUP
  ↓
BK-20260813-170500

can be traced back to:

operation:
REPAIR

70. Restore History

Record:

restore_operations

Eventually:

CREATE TABLE restore_operations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    site_id INTEGER NOT NULL,
    backup_id INTEGER NOT NULL,
    status TEXT NOT NULL,
    started_at TEXT NOT NULL,
    completed_at TEXT,
    result TEXT,
    FOREIGN KEY (site_id) REFERENCES sites(id),
    FOREIGN KEY (backup_id) REFERENCES backups(id)
);

71. Restore Status

Use:

PLANNED
VERIFYING
BACKING_UP_CURRENT
RESTORING
VALIDATING
RESTORED
FAILED
ROLLED_BACK

72. Restore Output

Successful:

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

Site:
example.com

Backup:
BK-20260813-170001-a8f3

Backup verification:
OK

Current-state safety backup:
OK

Files:
RESTORED

Database:
RESTORED

Configuration:
RESTORED

Health:
HEALTHY

Reconciliation:
MATCH

Result:
RESTORED

73. Failed Restore

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

Backup:
BK-20260813-170001-a8f3

Backup verification:
OK

Safety backup:
OK

Files:
RESTORED

Database:
FAILED

Rollback:
SUCCESS

Health:
HEALTHY

Result:
ROLLED_BACK

74. Restore Critical Failure

Database:
FAILED

Rollback:
FAILED

Current site:
UNKNOWN

Result:
CRITICAL

Manual intervention required.

Again, don’t hide the failure.


75. Backup Security

Backup directories should not be publicly accessible.

Never place:

/var/lib/cresignsys/backups

under:

/storage/websites/

or a public Nginx document root.


76. Backup Permissions

Use restrictive permissions.

For example:

directory:
0700

sensitive database dumps:
0600

The exact ownership should match the CHP service architecture.


77. Encrypt Sensitive Backups

Eventually, customer backups should support:

encryption at rest

especially for:

database dumps
private application data
customer uploads

Possible architecture:

Backup
  ↓
Compress
  ↓
Encrypt
  ↓
Store

Do not treat a plain SQL dump as safe merely because the filesystem is protected.


78. Encryption Key Management

Do not store:

encryption key

inside:

backup directory

Otherwise:

backup + key

means compromise of one location compromises both.

Key management should be a separate CHP security subsystem.


79. Off-Site Backups

Eventually:

LOCAL
  +
REMOTE

For example:

Server
 ↓
Local backup
 ↓
Object storage

The remote copy protects against:

disk failure
VM failure
server compromise
accidental deletion

80. Backup Architecture

The mature system becomes:

                   CHP BACKUP
                       │
             ┌─────────┴─────────┐
             ▼                   ▼
           LOCAL               REMOTE
             │                   │
             ▼                   ▼
        Fast Restore         Disaster Recovery

81. Backup Status in Site Status

Our previous:

hosting-site-status

can now display:

Backups
-------

Latest:
BK-20260813-170001

Status:
VERIFIED

Age:
2 hours

Local:
YES

Remote:
YES

Overall:
HEALTHY

82. Backup Warning

If:

Latest backup:
3 days old

then:

Backups:
WARNING

Even if:

Website:
HEALTHY

83. Backup Failure

If:

Last backup:
FAILED

and no newer backup exists:

Backups:
CRITICAL

This should affect the overall site status.


84. Updated Overall Model

We now have:

Runtime
Configuration
Backups
Resources

Example:

Runtime:
HEALTHY

Configuration:
MATCH

Backups:
WARNING

Resources:
HEALTHY

Overall:
WARNING

85. Repair Engine Integration

The repair engine can now do:

REPAIR PLAN
     ↓
APPROVAL
     ↓
PRE-REPAIR BACKUP
     ↓
REPAIR
     ↓
VERIFY

This is much safer than the previous architecture.


86. Restore Integration

If repair fails:

REPAIR
 ↓
FAILED
 ↓
ROLLBACK
 ↓
BACKUP RESTORE
 ↓
HEALTH CHECK
 ↓
RECONCILE

The backup engine therefore becomes part of the repair engine’s rollback infrastructure.


87. Complete CHP Safety Chain

                  REPAIR
                     │
                     ▼
                APPROVAL
                     │
                     ▼
                SAFETY BACKUP
                     │
                     ▼
                  CHANGE
                     │
                     ▼
                VALIDATION
                     │
                ┌────┴────┐
                ▼         ▼
              PASS      FAIL
                │         │
                ▼         ▼
             HEALTH    RESTORE
                │         │
                ▼         ▼
          RECONCILE    HEALTH
                │         │
                ▼         ▼
             VERIFIED  ROLLED_BACK

88. Lesson 087 — Core Principle

A backup is not just:

"some files copied somewhere."

A CHP backup must answer:

What site is this?
When was it created?
What exactly does it contain?
Can the files be verified?
Can the database be verified?
What environment created it?
Is it restorable?
Where is it stored?
How long should it be retained?

The most important distinction is:

CREATED
≠
VERIFIED
≠
RESTORABLE

That distinction will prevent CHP from falsely believing it has a usable recovery point.


Next Lesson — 088

Build the CHP Backup Scheduler & Retention Engine

Now that backup and restore exist, the next layer is automatic protection:

hosting-backup-schedule

with policies such as:

Daily:
02:00

Weekly:
Sunday

Monthly:
1st day

and retention:

7 daily
4 weekly
12 monthly

The scheduler will need to handle:

site-specific schedules
server-wide schedules
missed backups
concurrent backups
backup locks
retention
failed backups
storage limits
local + remote copies

and, importantly, it must never delete the last known-good recovery point just to satisfy a retention count.

Comments

Leave a Reply

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