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.
Leave a Reply