CresignSys Learn — Lesson 076

Written by

in

Build hosting-site-status

We now have separate diagnostic commands:

hosting-info DOMAIN
hosting-dns-check DOMAIN
hosting-health DOMAIN

The next step is to combine them into one site status engine.

Target:

sudo hosting-site-status example.com

1. Why hosting-site-status?

An administrator should not need to run:

hosting-info
hosting-dns-check
hosting-health
hosting-ssl
hosting-backup-list

individually just to understand one website.

Instead:

                    SITE STATUS
                         │
       ┌─────────────────┼─────────────────┐
       ▼                 ▼                 ▼
    DOMAIN              DNS              SERVER
       │                 │                 │
       ▼                 ▼                 ▼
     SSL               HTTP             PHP-FPM
       │                                   │
       └─────────────────┬─────────────────┘
                         ▼
                    APPLICATION
                         │
                         ▼
                      BACKUP
                         │
                         ▼
                    OVERALL STATE

2. Target Output

For a healthy site:

CresignSys Site Status
======================

Domain:
example.com

Overall:
HEALTHY

SERVICE
  State:       ACTIVE

DNS
  IPv4:        CORRECT
  IPv6:        NOT CONFIGURED

WEB
  Nginx:       OK
  HTTP:        OK
  HTTPS:       OK

SSL
  Status:      ACTIVE
  Certificate: VALID

PHP
  Version:     8.3
  PHP-FPM:     OK
  Socket:      OK

DATABASE
  MySQL:       OK
  WordPress DB: OK

APPLICATION
  WordPress:   OK

BACKUP
  Status:      HEALTHY
  Last Backup: 2026-08-13 16:00

FILES
  Web Root:    OK
  Ownership:   OK

Overall Health:
HEALTHY

3. Status Is Not the Same as Health

This distinction is important.

A site can be:

SERVICE_STATE=SUSPENDED
HEALTH_STATE=HEALTHY

That means:

The infrastructure is working, but the administrator intentionally suspended public access.

Therefore don’t collapse everything into one Boolean.


4. Site State Model

Use:

SERVICE_STATE

with:

ACTIVE
SUSPENDED
PROVISIONING
WAITING_DNS
ERROR
DELETING
DELETED

5. Health State Model

Use:

HEALTH_STATE

with:

HEALTHY
DEGRADED
CRITICAL
UNKNOWN

6. Example

Healthy active site

SERVICE_STATE=ACTIVE
HEALTH_STATE=HEALTHY

Suspended site

SERVICE_STATE=SUSPENDED
HEALTH_STATE=HEALTHY

DNS waiting

SERVICE_STATE=WAITING_DNS
HEALTH_STATE=DEGRADED

Database failure

SERVICE_STATE=ACTIVE
HEALTH_STATE=CRITICAL

This is much more expressive.


7. Status Categories

The unified checker should inspect:

1. Site metadata
2. Domain
3. DNS
4. Nginx
5. HTTP
6. HTTPS
7. SSL
8. PHP-FPM
9. PHP socket
10. Database
11. WordPress
12. Filesystem
13. Backup
14. Service state

8. Don’t Make Every Check Fatal

This is a common mistake.

Suppose:

DNS = PENDING

The script should not necessarily terminate.

It should continue:

DNS      PENDING
HTTP     UNKNOWN
HTTPS    UNKNOWN
PHP      OK
Database OK
WordPress OK

Then classify:

Overall:
WAITING_DNS

This gives much more useful information.


9. Check Execution Model

Use:

RUN CHECK
   │
   ├── PASS
   ├── WARN
   ├── FAIL
   └── UNKNOWN

Don’t immediately:

exit 1

after the first failure.


10. Check Result Structure

Each check should conceptually return:

NAME
STATUS
MESSAGE
SEVERITY

Example:

DNS
STATUS=FAIL
MESSAGE=Domain points to 198.51.100.20
SEVERITY=CRITICAL

11. Severity Levels

Use:

OK
WARNING
CRITICAL
UNKNOWN

Example:

DNS:
OK

SSL:
WARNING

Database:
CRITICAL

Overall health becomes:

CRITICAL

because the database is unavailable.


12. Overall Health Algorithm

A simple first version:

If any critical check fails:
    CRITICAL

Else if any warning exists:
    DEGRADED

Else:
    HEALTHY

If checks cannot be performed:

UNKNOWN

where appropriate.


13. Example

DNS          OK
Nginx        OK
HTTP         OK
HTTPS        OK
SSL          WARNING
PHP          OK
Database     OK
WordPress    OK
Backup       OK

Result:

HEALTH_STATE=DEGRADED

14. Example — Critical

DNS          OK
Nginx        OK
HTTP         500
HTTPS        500
SSL          OK
PHP          OK
Database     FAIL
WordPress    FAIL

Result:

HEALTH_STATE=CRITICAL

15. Example — Suspended

Service      SUSPENDED
DNS          OK
Nginx        OK
HTTPS        503
SSL          OK
Database     OK
WordPress    OK

Don’t report:

CRITICAL

if 503 is intentionally produced by the suspension configuration.

Report:

SERVICE_STATE=SUSPENDED
HEALTH_STATE=HEALTHY

16. Create Script

Create:

sudo nano /usr/local/bin/hosting-site-status

Start:

#!/usr/bin/env bash

set -Eeuo pipefail

17. Arguments

if [[ $# -ne 1 ]]; then
    echo "Usage: hosting-site-status DOMAIN"
    exit 1
fi

DOMAIN="$1"

Later we can add:

--json
--quiet
--verbose

18. Load Site Configuration

SITE_ROOT="/var/lib/cresignsys/sites/${DOMAIN}"
SITE_CONF="${SITE_ROOT}/site.conf"

if [[ ! -f "$SITE_CONF" ]]; then
    echo "ERROR: Site not found: $DOMAIN"
    exit 1
fi

source "$SITE_CONF"

19. Don’t Trust source Forever

There is an architectural warning here.

If:

site.conf

contains data controlled by an untrusted user, blindly doing:

source site.conf

can execute arbitrary shell commands.

For an administrator-controlled system this may be acceptable during early development, but a production multi-tenant platform should eventually use:

INI
JSON
SQLite
database

with safe parsing.


20. Site State

Read:

SERVICE_STATE

If missing:

SERVICE_STATE=UNKNOWN

Then display:

SERVICE
  State: ACTIVE

21. Domain Check

Verify:

DOMAIN

matches the requested site.

Don’t allow:

hosting-site-status example.com

to accidentally load:

shop.com

metadata.


22. DNS Check

Call the DNS checking logic.

Preferably don’t execute:

hosting-dns-check "$DOMAIN"

and parse its human-readable output.

Instead, create a reusable library:

/etc/cresignsys/lib/dns.sh

For example:

check_dns()

returns structured variables.


23. Why Libraries Matter

Without libraries:

hosting-health
hosting-site-status
hosting-ssl
hosting-domain-list

may all implement DNS checking differently.

That causes inconsistent results.

Better:

              dns.sh
                │
       ┌────────┼────────┐
       ▼        ▼        ▼
    health    status    ssl

24. Create Common Library

Directory:

sudo mkdir -p /etc/cresignsys/lib

Then:

sudo nano /etc/cresignsys/lib/dns.sh

Eventually:

dns.sh
domain.sh
nginx.sh
php.sh
mysql.sh
wordpress.sh
backup.sh
logging.sh
lock.sh

25. This Changes the Architecture

Instead of:

10 scripts
×
10 duplicated functions

we get:

10 commands
      │
      ▼
shared libraries
      │
      ▼
common behavior

This is a major improvement.


26. Nginx Check

Check service:

systemctl is-active --quiet nginx

If active:

Nginx:
OK

But this alone isn’t enough.

Nginx can be running while the site’s server block is broken.


27. Site-Specific Nginx Check

Verify the domain exists in the loaded Nginx configuration.

For example:

nginx -T

and inspect the generated configuration.

Don’t repeatedly run expensive full configuration dumps for every site on a large server.

Eventually maintain configuration metadata.


28. Better Nginx Check

Check:

site config exists
server_name exists
configuration enabled
nginx syntax valid

Then:

Nginx:
OK

29. HTTP Check

Use:

curl -I --max-time 10 "http://${DOMAIN}"

Possible result:

200
301
302
403
404
500
503

Not every non-200 response is necessarily a server failure.


30. HTTP Interpretation

For an active site:

200 → OK
301 → OK
302 → OK
403 → WARNING/possibly application policy
404 → WARNING
500 → CRITICAL
502 → CRITICAL
503 → CRITICAL

For a suspended site:

503 → EXPECTED

31. HTTPS Check

curl -Ik --max-time 10 "https://${DOMAIN}"

The -k option is useful for diagnostic separation when you want to test HTTP behavior even if certificate validation fails.

But don’t use -k to declare SSL healthy.

Certificate validation needs its own check.


32. SSL Check

Use:

openssl s_client

or an appropriate certificate inspection method.

Check:

certificate exists
certificate not expired
hostname covered
chain valid

33. SSL States

ACTIVE
EXPIRING_SOON
EXPIRED
MISMATCH
MISSING
ERROR

For example:

SSL:
EXPIRING_SOON

should be:

WARNING

while:

SSL:
EXPIRED

is:

CRITICAL

34. PHP-FPM Check

Find the configured PHP version:

PHP_VERSION=8.3

Then:

systemctl is-active php8.3-fpm

Expected:

PHP-FPM:
OK

35. PHP Socket Check

If your Nginx configuration uses:

/run/php/php8.3-fpm-example.com.sock

verify the socket exists.

For example:

PHP Socket:
OK

If:

Nginx → missing socket

you can get:

502 Bad Gateway

even though PHP-FPM itself is running.


36. Database Check

Check MySQL:

systemctl is-active --quiet mysql

Then test the site’s database credentials.

Don’t just check:

MySQL service = running

because the specific site’s database could still be inaccessible.


37. WordPress Database Check

Use:

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

Expected:

Database:
OK

38. WordPress Check

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

Then optionally:

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

Be aware that checksum verification may not be appropriate for sites with modified core files.


39. Filesystem Check

Verify:

WEB_ROOT exists
wp-config.php exists
permissions reasonable
owner correct
disk available

Example:

FILES
  Web Root: OK
  Ownership: OK
  Disk: OK

40. Disk Space

A site can be perfectly configured but fail because:

DISK = 100%

Check:

df -P "$WEB_ROOT"

Use thresholds.

For example:

< 80%  → OK
80-90% → WARNING
> 90%  → CRITICAL

These are policy examples and can be configurable.


41. Inode Usage

Disk capacity isn’t the only problem.

A server can have:

Disk:
50% used

but:

Inodes:
100% used

Then new files cannot be created.

Check:

df -Pi "$WEB_ROOT"

This should eventually be part of site health.


42. Backup Check

Read the backup inventory.

Check:

backup enabled?
last successful backup?
backup age?
backup verification status?

Example:

BACKUP
  Enabled:     YES
  Last:        2 hours ago
  Status:      HEALTHY

43. Backup Warning

Suppose:

Last backup:
10 days ago

while policy requires:

daily

Then:

Backup:
WARNING

Overall:

DEGRADED

44. Missing Backup

If:

BACKUP_ENABLED=true

but:

no valid backup exists

then:

Backup:
CRITICAL

depending on your hosting policy.


45. Status Summary

At the bottom:

================================

SERVICE:
ACTIVE

HEALTH:
HEALTHY

RESULT:
HEALTHY

Or:

SERVICE:
ACTIVE

HEALTH:
CRITICAL

RESULT:
CRITICAL

46. Machine-Readable Mode

This is extremely important for the future control panel.

Add:

sudo hosting-site-status example.com --json

Output:

{
  "domain": "example.com",
  "service_state": "ACTIVE",
  "health_state": "HEALTHY",
  "dns": "CORRECT",
  "nginx": "OK",
  "http": "OK",
  "https": "OK",
  "ssl": "ACTIVE",
  "php": "OK",
  "database": "OK",
  "wordpress": "OK",
  "backup": "HEALTHY"
}

47. Why JSON Matters

A future dashboard can consume:

hosting-site-status --json

without parsing:

[OK] Nginx
[OK] PHP

text.

This creates a clean boundary:

CHP Engine
     ↓
JSON
     ↓
Dashboard

48. Don’t Build the Dashboard Yet

First make the CLI engine reliable.

The future dashboard can then be:

Web UI
   ↓
API
   ↓
CHP Engine

rather than duplicating all hosting logic in PHP/JavaScript.


49. Exit Codes

The command should also return useful exit codes.

For example:

0 = HEALTHY
1 = DEGRADED
2 = CRITICAL
3 = UNKNOWN

Then automation can do:

if hosting-site-status example.com --quiet; then
    echo "Healthy"
fi

50. Why Exit Codes Matter

Monitoring systems don’t read pretty terminal output.

They need:

0
1
2

to decide whether an alert should be triggered.

This allows later integration with monitoring systems.


51. Quiet Mode

Add:

sudo hosting-site-status example.com --quiet

Output:

HEALTHY

or nothing except an error.

This is useful for scripts.


52. Verbose Mode

Add:

sudo hosting-site-status example.com --verbose

to show:

DNS query
resolver
IP addresses
TTL
Nginx server block
PHP socket
database connection
certificate details
backup age
disk usage

53. Normal Mode Should Stay Simple

Normal:

hosting-site-status example.com

should be readable.

Don’t dump 200 lines of technical information by default.


54. Example — Healthy

CresignSys Site Status
======================

example.com

SERVICE
  State:       ACTIVE

DNS
  Status:      CORRECT

WEB
  Nginx:       OK
  HTTP:        OK
  HTTPS:       OK

SSL
  Status:      ACTIVE

PHP
  PHP-FPM:     OK
  Socket:      OK

DATABASE
  MySQL:       OK
  WordPress:   OK

FILES
  Web Root:    OK
  Ownership:   OK
  Disk:        OK

BACKUP
  Status:      HEALTHY
  Last:        2 hours ago

--------------------------------
OVERALL: HEALTHY

55. Example — Waiting for DNS

CresignSys Site Status
======================

example.com

SERVICE
  State:       WAITING_DNS

DNS
  Status:      PENDING

WEB
  Nginx:       OK
  HTTP:        UNKNOWN
  HTTPS:       UNKNOWN

SSL
  Status:      PENDING

PHP
  PHP-FPM:     OK

DATABASE
  MySQL:       OK

APPLICATION
  WordPress:   OK

BACKUP
  Status:      HEALTHY

--------------------------------
OVERALL: WAITING_DNS

This is much more useful than simply saying:

ERROR

56. Example — Database Failure

example.com

SERVICE
  State:       ACTIVE

DNS
  Status:      CORRECT

WEB
  Nginx:       OK
  HTTP:        500
  HTTPS:       500

PHP
  PHP-FPM:     OK

DATABASE
  MySQL:       FAIL

APPLICATION
  WordPress:   FAIL

BACKUP
  Status:      HEALTHY

--------------------------------
OVERALL: CRITICAL

57. Example — Suspended

example.com

SERVICE
  State:       SUSPENDED

DNS
  Status:      CORRECT

WEB
  Nginx:       OK
  HTTPS:       EXPECTED_503

SSL
  Status:      ACTIVE

PHP
  PHP-FPM:     OK

DATABASE
  MySQL:       OK

APPLICATION
  WordPress:   OK

BACKUP
  Status:      HEALTHY

--------------------------------
OVERALL: SUSPENDED

58. Important: Expected Failures

This is a major monitoring principle.

A suspended site returning:

503

isn’t necessarily a failure.

Similarly:

HTTP 301

isn’t necessarily a failure.

The checker needs context.

HTTP result
+
SERVICE_STATE
+
DOMAIN_TYPE

determines the meaning.


59. Redirect Domain

For:

old.example.com

the expected HTTP result might be:

301

Therefore:

301 = OK

for a redirect domain.

This is why checks must understand domain type.


60. Alias Domain

For:

www.example.com

expected:

200

or perhaps:

301 → example.com

depending on your canonical URL policy.

Again, the status engine needs metadata.


61. Domain Policy

Add:

CANONICAL=true
REDIRECT_TARGET=

or equivalent domain metadata.

Then health checks know what response is expected.


62. Status Engine Architecture

The internal model becomes:

                   SITE STATUS
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
        Metadata      Domain       Service
          │            │            │
          ▼            ▼            ▼
       Policy         DNS          State
                       │
                       ▼
                    Web Layer
                       │
             ┌─────────┼─────────┐
             ▼         ▼         ▼
           HTTP       HTTPS      SSL
                       │
                       ▼
                  Application
                       │
              ┌────────┼────────┐
              ▼        ▼        ▼
             PHP       DB     WordPress
                       │
                       ▼
                    Backup
                       │
                       ▼
                 Health Engine

63. Shared Libraries

At this stage, create:

/etc/cresignsys/lib/
├── common.sh
├── domain.sh
├── dns.sh
├── nginx.sh
├── php.sh
├── mysql.sh
├── wordpress.sh
├── backup.sh
├── ssl.sh
├── logging.sh
└── lock.sh

This is a major architectural milestone.


64. common.sh

Put shared functions such as:

log_info()
log_warn()
log_error()
die()
require_root()
command_exists()

there.


65. domain.sh

Functions:

validate_domain()
normalize_domain()
domain_exists()
site_exists()

66. dns.sh

Functions:

get_a_records()
get_aaaa_records()
get_cname()
get_nameservers()
check_dns()

67. nginx.sh

Functions:

nginx_is_running()
nginx_config_valid()
site_config_exists()
reload_nginx()

68. php.sh

Functions:

php_fpm_is_running()
php_socket_exists()
get_php_version()

69. mysql.sh

Functions:

mysql_is_running()
database_exists()
database_connection_test()

70. wordpress.sh

Functions:

wordpress_is_installed()
wordpress_db_check()
wordpress_core_check()

71. backup.sh

Functions:

latest_backup()
backup_exists()
backup_is_valid()
backup_age()

72. ssl.sh

Functions:

certificate_exists()
certificate_expiry()
certificate_matches_domain()

73. logging.sh

Functions:

audit_log()
operation_log()

74. lock.sh

Functions:

acquire_site_lock()
release_site_lock()

This prevents duplicate locking logic across scripts.


75. Command Layer

Now the commands become relatively thin:

hosting-create
      ↓
common libraries

hosting-health
      ↓
common libraries

hosting-site-status
      ↓
common libraries

This is a much cleaner architecture than having every command contain thousands of lines of Bash.


76. Future API

Once the CLI is structured this way:

CHP Core
   │
   ├── CLI
   │
   ├── API
   │
   └── Dashboard

can all use the same underlying state and logic.


77. The Future Control Panel

The dashboard can eventually display:

CresignSys Hosting
────────────────────────────────

Sites       42
Healthy     37
Degraded     3
Critical     1
Suspended    1

DNS Issues   2
SSL Issues   1
Backup Issues 1

Click:

example.com

and get the complete status.


78. Monitoring

The status engine also allows scheduled monitoring:

every 5 minutes
      ↓
hosting-site-status
      ↓
problem?
      ↓
alert

For example:

Database failure detected
Domain: example.com
Time: 18:42

79. Avoid Alert Spam

If a site remains broken for:

30 minutes

don’t send:

360 alerts

Instead use state transitions:

HEALTHY
   ↓
CRITICAL

send alert.

Then:

CRITICAL
   ↓
CRITICAL

don’t repeatedly alert unless configured.

Then:

CRITICAL
   ↓
HEALTHY

send recovery notification.


80. Status History

Eventually store:

site_id
timestamp
health_state
reason

Example:

18:00 HEALTHY
18:42 CRITICAL DATABASE
18:47 CRITICAL DATABASE
18:53 HEALTHY

This creates a basic uptime history.


81. Uptime Percentage

Once history exists:

total monitoring time
-
downtime

can calculate:

99.9%
99.95%
99.99%

This can eventually become a hosting dashboard metric.


82. Lesson 076 — Core Principle

hosting-site-status should become the single source of operational truth for a website.

It combines:

DOMAIN
DNS
NGINX
HTTP
HTTPS
SSL
PHP
DATABASE
WORDPRESS
FILES
BACKUP
SERVICE STATE

and converts those individual signals into:

HEALTHY
DEGRADED
CRITICAL
SUSPENDED
WAITING_DNS

83. Updated CHP Command Set

hosting-create DOMAIN

hosting-list
hosting-info DOMAIN
hosting-site-status 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

hosting-domain-add DOMAIN
hosting-domain-add DOMAIN --alias TARGET
hosting-domain-add DOMAIN --redirect TARGET
hosting-domain-list DOMAIN
hosting-domain-remove DOMAIN

hosting-dns-check DOMAIN

Next Lesson — 077

Build the Shared CHP Core Library

We have reached the point where continuing to add standalone Bash scripts will create duplicated code.

The next lesson should therefore consolidate the platform into:

/etc/cresignsys/
├── config/
├── lib/
│   ├── common.sh
│   ├── domain.sh
│   ├── dns.sh
│   ├── nginx.sh
│   ├── php.sh
│   ├── mysql.sh
│   ├── wordpress.sh
│   ├── ssl.sh
│   ├── backup.sh
│   ├── logging.sh
│   └── lock.sh
├── templates/
│   ├── nginx/
│   ├── php/
│   └── suspended/
└── sites/

and:

/usr/local/bin/
├── hosting-create
├── hosting-list
├── hosting-info
├── hosting-health
├── hosting-site-status
├── hosting-repair
├── hosting-ssl
├── hosting-backup
├── hosting-restore
├── hosting-suspend
├── hosting-unsuspend
├── hosting-domain-add
├── hosting-domain-list
├── hosting-domain-remove
└── hosting-dns-check

The goal is to move from a collection of scripts to a real CresignSys Hosting Platform core with shared validation, locking, logging, configuration, state management, and reusable service functions.

Comments

Leave a Reply

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