CresignSys Learn — Lesson 073

Written by

in

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.

Comments

Leave a Reply

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