Build hosting-suspend and hosting-unsuspend
We now have:
hosting-create
hosting-list
hosting-info
hosting-health
hosting-repair
hosting-ssl
hosting-backup
hosting-backup-list
hosting-backup-verify
hosting-backup-prune
hosting-restore
The next lifecycle feature is:
sudo hosting-suspend example.com
and:
sudo hosting-unsuspend example.com
The central rule is:
Suspension disables service; it does not delete customer data.
1. Why Suspension?
A hosting platform needs to temporarily disable a website for situations such as:
Payment overdue
Abuse investigation
Customer request
Maintenance
Security incident
Resource violation
Administrative action
But the website must remain recoverable.
2. Suspension vs Deletion
These are completely different.
Suspend
Website access
↓
BLOCKED
Files preserved
Database preserved
SSL preserved
Backups preserved
Configuration preserved
Delete
Website
↓
data removal
↓
configuration removal
Therefore:
hosting-suspend
≠
hosting-delete
3. Site State Machine
Our site lifecycle now becomes:
┌─────────────┐
│ CREATED │
└──────┬──────┘
│
▼
ACTIVE
│ │
suspend │ │ repair
▼ │
SUSPENDED│
│ │
unsuspend │ │
▼ │
ACTIVE │
│
▼
DELETED
4. Important States
Use explicit states:
PROVISIONING
ACTIVE
SUSPENDING
SUSPENDED
UNSUSPENDING
ERROR
DELETING
DELETED
This is better than only:
active=true
5. Suspension Architecture
The safe sequence:
hosting-suspend example.com
│
▼
Verify site
│
▼
Acquire lock
│
▼
Optional final backup
│
▼
Set SUSPENDING
│
▼
Disable website access
│
▼
Validate configuration
│
▼
Set SUSPENDED
6. What Should Suspension Do?
For the first CHP implementation:
HTTP access blocked
HTTPS access blocked
PHP execution unavailable through site
Files preserved
Database preserved
SSL preserved
Backups preserved
DNS unchanged
7. What Should Suspension NOT Do?
Do not:
delete files
drop database
delete SSL
delete DNS
delete backups
remove site metadata
The entire point is reversibility.
8. Why Not Delete DNS?
Suppose:
example.com
↓
SERVER IP
During suspension, leave DNS alone.
Changing DNS introduces unnecessary propagation delays and makes unsuspension less predictable.
9. Suspension Methods
There are several ways to block the site.
Method A — Nginx suspension page
HTTP/HTTPS
↓
Nginx
↓
Suspension page
Method B — firewall
Internet
↓
firewall
↓
BLOCK
Method C — remove Nginx configuration
Not recommended.
For CHP:
Prefer an Nginx suspension configuration.
10. Why Nginx Is Better Here
We want:
DNS → server
to remain valid.
Nginx can respond:
HTTP 403
or:
HTTP 503
with:
Website temporarily unavailable
This is easier to reverse.
11. HTTP Status Code
For a suspended website, use:
503 Service Unavailable
rather than:
404 Not Found
Why?
Because the website hasn’t disappeared.
It is temporarily unavailable.
12. Suspension Page
Create a centralized page:
/etc/cresignsys/suspended/index.html
Example:
<!DOCTYPE html>
<html>
<head>
<title>Website Temporarily Unavailable</title>
</head>
<body>
<h1>Website Temporarily Unavailable</h1>
<p>This website has been temporarily suspended.</p>
</body>
</html>
Later you can make this branded as:
CresignSys Hosting
13. Don’t Put Suspension Pages in Every Website
Avoid:
example.com/public/suspended.html
shop.com/public/suspended.html
site3.com/public/suspended.html
Instead use:
/etc/cresignsys/suspended/
This makes the infrastructure centrally managed.
14. Nginx Suspension Configuration
Conceptually:
location / {
return 503;
}
error_page 503 /suspended.html;
location = /suspended.html {
root /etc/cresignsys/suspended;
internal;
}
This causes the website to respond with a suspension page.
The exact configuration should be incorporated into your CHP Nginx template rather than manually appended to arbitrary configurations.
15. Preserve HTTPS
If the site already has:
HTTPS
don’t remove the certificate.
The suspended site should still be able to respond over:
https://example.com
with:
503 Service Unavailable
This prevents unnecessary certificate reissuance when the site is unsuspended.
16. Why Preserve SSL?
Without this:
SUSPEND
↓
delete HTTPS configuration
↓
UNSUSPEND
↓
request certificate again
creates unnecessary complexity.
Better:
SUSPEND
↓
HTTPS remains
↓
503
↓
UNSUSPEND
↓
normal HTTPS
17. Create hosting-suspend
Create:
sudo nano /usr/local/bin/hosting-suspend
Start:
#!/usr/bin/env bash
set -Eeuo pipefail
18. Root Check
if [[ "$EUID" -ne 0 ]]; then
echo "ERROR: Run with sudo."
exit 1
fi
19. Domain Argument
if [[ $# -ne 1 ]]; then
echo "Usage: hosting-suspend DOMAIN"
exit 1
fi
DOMAIN="$1"
20. Load Site Metadata
STATE_DIR="/var/lib/cresignsys/sites"
SITE_DIR="${STATE_DIR}/${DOMAIN}"
SITE_CONF="${SITE_DIR}/site.conf"
if [[ ! -f "$SITE_CONF" ]]; then
echo "ERROR: Site not found."
exit 1
fi
source "$SITE_CONF"
21. Check Current State
If:
STATUS=SUSPENDED
then:
hosting-suspend example.com
should return:
Site is already suspended.
It should not perform the operation again unnecessarily.
This is idempotency.
22. Don’t Suspend a Site While Provisioning
If:
STATUS=PROVISIONING
don’t allow:
hosting-suspend
The state machine should reject invalid transitions.
For example:
PROVISIONING → SUSPENDED
should not be allowed.
23. Valid Suspension Transition
ACTIVE
↓
SUSPENDING
↓
SUSPENDED
If an error occurs:
SUSPENDING
↓
ERROR
The system must record what happened.
24. Acquire Lock
Use the site lock:
/var/lock/cresignsys-example.com.lock
This prevents:
hosting-suspend
from racing with:
hosting-backup
hosting-repair
hosting-restore
hosting-delete
25. Optional Final Backup
Before suspension, you can optionally create a final backup:
ACTIVE
↓
BACKUP
↓
SUSPEND
This is useful for administrative actions.
However, don’t make this mandatory for every suspension if it creates unnecessary storage/cost.
A configurable policy is better:
SUSPEND_BACKUP=true
26. Set State
Before modifying Nginx:
STATUS=SUSPENDING
This prevents another operation from treating the site as fully active during the transition.
27. Generate Suspended Configuration
Don’t manually edit:
/etc/nginx/sites-available/example.com.conf
with random sed operations.
Instead:
Current site metadata
↓
Nginx template
↓
MODE=SUSPENDED
↓
Generate temporary config
28. Template Architecture
Your Nginx template can eventually support:
MODE=ACTIVE
MODE=SUSPENDED
For example:
/etc/cresignsys/templates/nginx-site.conf
The template chooses the correct behavior.
29. Why Template-Based Suspension?
Without a template:
hosting-create
hosting-ssl
hosting-repair
hosting-suspend
hosting-unsuspend
could each modify Nginx differently.
Eventually the configuration becomes inconsistent.
One source of truth is safer.
30. Generate Temporary Configuration
Example:
/etc/nginx/sites-available/example.com.conf.tmp
Then:
nginx -t
Only if successful:
.tmp
↓
actual configuration
31. Reload Nginx
systemctl reload nginx
A reload is preferable to restarting the entire Nginx service because existing connections can be handled more gracefully.
32. Verify Suspension
Run:
curl -I https://example.com
Expected:
HTTP/2 503
or an equivalent configured response.
33. Verify HTTP
Also:
curl -I http://example.com
Depending on your architecture, HTTP may:
HTTP → HTTPS → 503
which is perfectly acceptable.
The important thing is that the application is unavailable while HTTPS remains functional.
34. Set Final State
Only after verification:
STATUS=SUSPENDED
If the health test fails unexpectedly:
STATUS=ERROR
and investigate.
35. Suspension Output
A successful result:
CresignSys Suspend
==================
Domain: example.com
[OK] Site verified
[OK] Site lock acquired
[OK] Pre-suspension backup
[OK] Suspension configuration generated
[OK] nginx -t
[OK] Nginx reloaded
[OK] HTTPS returns 503
Status: SUSPENDED
36. What the User Sees
Instead of their WordPress site:
Website Temporarily Unavailable
This website has been temporarily suspended.
Please contact the hosting administrator.
37. Better Suspension Page
Eventually use:
CresignSys Hosting
------------------
Website Temporarily Unavailable
Domain:
example.com
Reason:
This website is currently suspended.
Contact:
support@example.com
However, be careful about exposing internal administrative information or suspension reasons publicly.
38. Don’t Expose Sensitive Reasons
Avoid displaying:
Payment overdue by ₹4,521
Abuse report #12345
Security incident details
on a public suspension page.
Use generic messaging:
This website is temporarily unavailable.
Please contact the hosting provider.
39. Build hosting-unsuspend
Create:
sudo nano /usr/local/bin/hosting-unsuspend
Start with the same structure:
#!/usr/bin/env bash
set -Eeuo pipefail
40. Check State
If:
STATUS=ACTIVE
then:
Site is already active.
If:
STATUS=SUSPENDED
continue.
41. Unsuspend Workflow
SUSPENDED
↓
Acquire lock
↓
UNSUSPENDING
↓
Generate ACTIVE Nginx configuration
↓
nginx -t
↓
reload nginx
↓
HTTP/HTTPS test
↓
health check
↓
ACTIVE
42. Important: Don’t Just Flip the Database Flag
This is insufficient:
STATUS=ACTIVE
because the Nginx configuration may still be:
MODE=SUSPENDED
The actual service state and metadata state must agree.
43. Configuration + State Must Change Together
Correct:
Generate active configuration
↓
Validate
↓
Reload
↓
Health check
↓
STATUS=ACTIVE
Incorrect:
STATUS=ACTIVE
↓
Nginx still suspended
44. Unsuspend Validation
Test:
curl -I https://example.com
Expected:
HTTP/2 200
or:
HTTP/2 301
depending on the application.
It should no longer return:
503
45. Run Full Health Check
After unsuspending:
hosting-health example.com
Expected:
[OK] DNS
[OK] Nginx
[OK] PHP-FPM
[OK] PHP socket
[OK] WordPress
[OK] Database
[OK] HTTPS
Only then:
STATUS=ACTIVE
46. Unsuspend Output
CresignSys Unsuspend
====================
Domain: example.com
[OK] Site verified
[OK] Site lock acquired
[OK] Active configuration generated
[OK] nginx -t
[OK] Nginx reloaded
[OK] HTTPS response
[OK] Full health check
Status: ACTIVE
47. What If Unsuspend Fails?
Suppose:
Nginx configuration
↓
FAIL
Then:
SUSPENDED
should remain the logical state.
Do not say:
ACTIVE
until the site actually works.
48. Unsuspend Failure Model
SUSPENDED
↓
UNSUSPENDING
↓
configuration error
↓
restore previous suspended config
↓
STATUS=SUSPENDED
This is safer.
49. Suspension Must Be Reversible
The key requirement:
ACTIVE
↓
SUSPEND
↓
SUSPENDED
↓
UNSUSPEND
↓
ACTIVE
should work repeatedly.
For example:
ACTIVE
→ SUSPENDED
→ ACTIVE
→ SUSPENDED
→ ACTIVE
without configuration accumulating duplicate directives.
50. Avoid sed-Based Toggle Logic
Bad design:
sed -i 's/return 503/#return 503/' ...
Then another command:
sed -i ...
After multiple operations, the configuration becomes fragile.
Better:
site metadata
↓
template
↓
desired state
↓
complete configuration
51. Desired-State Model
This is an important platform architecture.
Instead of asking:
What changes should I make?
ask:
What should the final state look like?
For example:
DESIRED_STATE=ACTIVE
or:
DESIRED_STATE=SUSPENDED
Then regenerate configuration from that state.
52. This Helps Repair
Suppose Nginx is manually changed and becomes incorrect.
hosting-repair can simply say:
Desired state:
ACTIVE
and regenerate the correct configuration.
If suspended:
Desired state:
SUSPENDED
and repair generates the suspended configuration.
This integrates suspension with the repair system.
53. Site Metadata
Add:
SERVICE_STATE=ACTIVE
or:
SERVICE_STATE=SUSPENDED
You could also use:
STATUS=ACTIVE
SUSPENDED=false
but avoid maintaining duplicate state variables unless necessary.
Prefer one authoritative state.
54. Suspension Reason
You may want:
SUSPENSION_REASON=ADMINISTRATIVE
Possible values:
ADMINISTRATIVE
PAYMENT
SECURITY
ABUSE
MAINTENANCE
CUSTOMER_REQUEST
But this should be internal metadata.
55. Suspension Timestamp
Store:
SUSPENDED_AT=2026-08-13T18:30:00
Then:
hosting-info example.com
can display:
Status:
SUSPENDED
Since:
2026-08-13 18:30
56. Suspension Operator
Audit information can include:
SUSPENDED_BY=admin
or an internal operator identity.
This is useful for a multi-admin hosting platform.
57. Audit Log
Every lifecycle change should be recorded.
Example:
2026-08-13 18:30
SUSPEND
example.com
operator=admin
reason=MAINTENANCE
Then:
2026-08-13 19:15
UNSUSPEND
example.com
operator=admin
58. Why Audit Logs Matter
If someone asks:
Why is this website suspended?
you can determine:
who
when
why
without relying on memory or shell history.
59. hosting-info Enhancement
It should now show:
Domain : example.com
Status : SUSPENDED
Suspended Since : 2026-08-13 18:30
Reason : MAINTENANCE
Web Root : /storage/websites/example.com/public
PHP : 8.3
SSL : ACTIVE
Backups : ENABLED
60. hosting-list Enhancement
Instead of:
example.com
shop.com
learn.com
show:
DOMAIN STATUS
---------------------------------------
example.com ACTIVE
shop.com SUSPENDED
learn.com ACTIVE
This becomes much more useful operationally.
61. Backup During Suspension
Should backups continue?
Generally:
SUSPENDED
↓
BACKUP
should remain possible.
Why?
The site’s data still exists and should remain protected.
However, your scheduled backup policy may decide whether suspended sites receive normal backups.
62. Recommended Policy
For an actively suspended site:
Existing backups:
PRESERVE
Manual backup:
ALLOW
Restore:
ALLOW ADMIN
Scheduled backups:
CONFIGURABLE
Don’t automatically delete backups merely because the site is suspended.
63. Restore a Suspended Site
This should be allowed.
Example:
SUSPENDED
↓
hosting-restore
After restoration:
SUSPENDED
should remain suspended unless the administrator explicitly requests unsuspension.
This is important.
64. Why Restore Shouldn’t Unsuspend
Suppose an administrator restores a suspended customer site.
It would be dangerous if:
restore
↓
ACTIVE
automatically.
The intended state was:
SUSPENDED
Therefore:
restore data
+
preserve lifecycle state
is the safer model.
65. Repair a Suspended Site
Similarly:
SUSPENDED
↓
hosting-repair
can repair infrastructure without automatically making the website publicly available.
Desired state remains:
SUSPENDED
66. SSL Renewal for Suspended Sites
This introduces an interesting issue.
A suspended site may still have an SSL certificate that needs renewal.
Therefore:
SUSPENDED
doesn’t necessarily mean:
SSL automation stops
If the certificate must remain valid for future unsuspension, renewal may need to continue.
67. Better State Separation
This reveals why we shouldn’t combine everything into one state.
Use separate concepts:
SERVICE_STATE
ACTIVE / SUSPENDED
SSL_STATE
ACTIVE / ERROR
BACKUP_STATE
HEALTHY / ERROR
HEALTH_STATE
HEALTHY / DEGRADED
Then:
SERVICE_STATE=SUSPENDED
SSL_STATE=ACTIVE
BACKUP_STATE=HEALTHY
is perfectly valid.
68. This Is Better Than One STATUS
Instead of:
STATUS=SUSPENDED
meaning everything, maintain:
SERVICE_STATE=SUSPENDED
HEALTH_STATE=HEALTHY
SSL_STATE=ACTIVE
BACKUP_STATE=HEALTHY
Now the platform knows exactly what is happening.
69. Example Dashboard
example.com
Service SUSPENDED
Health HEALTHY
SSL ACTIVE
Backup HEALTHY
Database ONLINE
PHP-FPM ONLINE
This is much more informative.
70. Suspension and Database
Do not stop MySQL globally.
Never do:
systemctl stop mysql
because one website is suspended.
The server hosts multiple websites.
Instead:
example.com
↓
application access blocked
shop.com
↓
continues working
71. Suspension and PHP-FPM
Likewise, don’t stop:
systemctl stop php8.3-fpm
because one website is suspended.
That would potentially affect every site using PHP 8.3.
The suspension should happen at the site configuration layer.
72. Multi-Tenant Principle
This is a critical hosting-platform rule:
A per-site operation must not unnecessarily disrupt other sites.
Therefore:
Suspend example.com
should affect:
example.com
not:
shop.com
learn.com
medical.example.com
73. Nginx Isolation
Because each site has its own server block:
example.com
shop.com
learn.com
you can suspend one site without affecting the others.
This is one reason the per-domain Nginx configuration architecture is useful.
74. Error Handling
If:
nginx -t
fails while suspending:
Don't reload.
Don't change service state.
Preserve working configuration.
The safe workflow remains:
generate
↓
validate
↓
activate
75. Lesson 073 — Core Principle
Suspension should be:
REVERSIBLE
SITE-SPECIFIC
NON-DESTRUCTIVE
AUDITABLE
Therefore:
hosting-suspend
means:
block access
+
preserve data
+
preserve SSL
+
preserve backups
+
preserve configuration
and:
hosting-unsuspend
means:
restore desired active configuration
+
validate
+
health check
+
activate
76. Updated CHP Architecture
The platform now has:
CHP
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
Provisioning Operations Recovery
│ │ │
▼ ▼ ▼
hosting-create hosting-health hosting-backup
hosting-list hosting-repair hosting-restore
hosting-info hosting-ssl backup-list
backup-verify
backup-prune
│
▼
Lifecycle
│
┌────────┴────────┐
▼ ▼
suspend unsuspend
77. 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-backup-list DOMAIN
hosting-backup-verify DOMAIN BACKUP_ID
hosting-backup-prune DOMAIN --dry-run
hosting-backup-prune DOMAIN --execute
hosting-restore DOMAIN BACKUP_ID
hosting-suspend DOMAIN
hosting-unsuspend DOMAIN
Next Lesson — 074
Build hosting-domain
The next major requirement is domain management.
We need to separate:
SERVER
│
├── IP
├── Nginx
├── PHP
├── MySQL
└── SSL
from:
SITE
│
├── domain
├── aliases
├── document root
├── DNS requirements
└── SSL names
The next layer will handle:
sudo hosting-domain-add example.com
sudo hosting-domain-add www.example.com --alias example.com
sudo hosting-domain-list example.com
sudo hosting-domain-remove example.com
and establish the relationship:
SITE
│
┌──────────┼──────────┐
▼ ▼ ▼
Primary Alias Redirect
Domain Domain Domain
│ │ │
└──────────┼──────────┘
▼
Nginx
│
▼
SSL
This is necessary before building a proper multi-domain WordPress hosting platform.
Leave a Reply