atillalab/site-health

A fast CLI for checking website and domain health.

20

stars

58

commits

Go

primary language

Aug 29, 2026

updated

README

site-health

A fast CLI for checking website and domain health.

Status: Go rewrite complete (v0.16.1)

Quick Start

site-health example.com
site-health --verbose example.com
site-health --mail example.com
site-health --whois example.com
site-health --skip-mail example.com
site-health --mail-checks spf example.com
site-health --skip-redirect example.com
site-health --format json example.com
site-health --doctor
site-health --init-config
site-health web
site-health web --port 8081

Features

Zero external dependencies — stdlib only:

  • Domain registration expiry
  • Registrar lookup
  • Optional verbose output for troubleshooting
  • DNS resolution (A, AAAA, CNAME)
  • TCP connectivity (80/443)
  • HTTP/HTTPS availability
  • Redirect and canonical host validation
  • SSL certificate validation
  • Response time measurement
  • HTML content validation
  • Common server/PHP/WordPress error detection
  • Parked domain detection
  • Final summary with failure and warning counts
  • MX record lookup, including Null MX recognition
  • SPF TXT record validation
  • DMARC TXT record validation
  • Mail checks skippable in site mode with --skip-mail
  • Individual mail checks selectable with --mail-checks and --skip-mail-checks
  • WHOIS-only mode with --whois for domain registration checks without HTTP probes
  • Optional /llms.txt availability check (skippable with --skip-llms-txt)
  • Canonical redirect check skippable with --skip-redirect
  • Machine-readable JSON output for automation and monitoring
  • Config file and environment variables for default flags
  • Self-diagnostic --doctor mode for the binary and local environment
  • Local web UI for project-based checks and session history (site-health web)

Usage

Run the full website/domain health check. By default, output is a concise dashboard:

site-health example.com

Example:

Site Health Check
Domain: example.com
Expected Hosts: example.com

SITE HEALTH
───────────
● example.com
  DNS          OK
  HTTPS        OK
  SSL          81 days
  Domain Reg   757 days (14 Sep 2028)
  Redirect     OK
  Response     184 ms
  Mail         OK
Status: HEALTHY

When a forwarded or explicit canonical URL matters, the dashboard includes it:

Site Health Check
Domain: example.com
Expected Hosts: example.org

SITE HEALTH
───────────
● example.com
  DNS          OK
  HTTPS        OK
  SSL          81 days
  Domain Reg   757 days (14 Sep 2028)
  Redirect     OK
  Response     184 ms
  Mail         OK
Status: HEALTHY

Show detailed troubleshooting diagnostics instead of the dashboard:

site-health --verbose example.com

Run only mail-related DNS checks:

site-health --mail example.com

Mail mode checks only:

  • MX
  • SPF
  • DMARC

Example:

MAIL HEALTH
───────────
● example.com
  MX           OK
  SPF          OK
  DMARC        WARN
Status: WARNING

Show detailed mail diagnostics:

site-health --mail --verbose example.com

Run only WHOIS / domain-registration checks:

site-health --whois example.com

WHOIS mode checks only:

  • Domain registration expiry
  • Registrar

Example:

WHOIS / Domain Registration
─────────────────────────
● example.com
  Domain Reg   350 days (13 Aug 2027)
  Registrar    RESERVED-Internet Assigned Numbers Authority
Status: HEALTHY

Show detailed WHOIS diagnostics:

site-health --whois --verbose example.com

Run only selected mail checks:

site-health --mail-checks spf example.com
site-health --mail-checks mx,dmarc example.com
site-health --mail --mail-checks spf example.com

Skip selected mail checks:

site-health --skip-mail-checks spf example.com
site-health --mail --skip-mail-checks spf example.com

The supported mail check names are mx, spf, and dmarc. --mail-checks and --skip-mail-checks filter the mail portion of the current run. Use them with --mail for mail-only output, or without --mail for a full site health run with filtered mail checks. Use --skip-mail when you want a full site health run without mail checks.

Skip mail-related DNS checks in a full site health run:

site-health --skip-mail example.com

This skips MX, SPF, and DMARC checks when mail health is outside the monitoring scope. For domains you control that deliberately do not send or receive mail, explicit no-mail DNS policy is still preferred: Null MX, SPF -all, and DMARC p=reject.

Skip the optional /llms.txt check:

site-health --skip-llms-txt example.com

Skip the canonical redirect check when the site intentionally serves the same content from multiple URL variants (for example, both https://example.com and https://www.example.com):

site-health --skip-redirect example.com

This keeps HTTPS, response-time, and SSL checks running, but does not enforce a single canonical URL. Use it for domains where redirecting every variant to one URL is not desired.

Forwarded domains are detected automatically when the final URL is unambiguous:

site-health example.com

To strictly require a specific final host, provide it explicitly:

site-health --expected-hosts example.org example.com

When a site intentionally serves the same content from multiple hosts (for example, both https://example.com and https://www.example.com), pass them as a comma-separated list. The singular --expected-host is also accepted as an alias:

site-health --expected-hosts example.com,www.example.com example.com

Output a machine-readable JSON document instead of the dashboard (useful for scripts, CI, and monitoring). --verbose output is suppressed in JSON mode; the same exit codes apply (0 healthy, 1 issues found):

site-health --format json example.com

Example:

{
  "tool": "site-health",
  "version": "0.16.1",
  "domain": "example.com",
  "mode": "site",
  "expected_hosts": ["example.com"],
  "forwarding": {
    "auto_detected": false,
    "ambiguous": false,
    "candidates": []
  },
  "checks": {
    "dns": { "status": "OK", "a": ["104.20.23.154"], "aaaa": [] },
    "https": { "status": "OK" },
    "ssl": { "status": "OK", "days_remaining": 81, "subject": "CN=example.com" },
    "redirect": { "status": "OK" },
    "response": { "status": "OK", "ms": 184 },
    "domain_registration": {
      "status": "OK",
      "registrar": "MarkMonitor Inc.",
      "expires_at": "2028-09-14T04:00:00Z",
      "days_remaining": 757
    },
    "mail": {
      "status": "OK",
      "mx": { "status": "OK", "records": ["0 ."] },
      "spf": { "status": "OK", "records": ["v=spf1 -all"] },
      "dmarc": { "status": "OK", "records": ["v=DMARC1;p=reject"] }
    }
  },
  "issues": [],
  "summary": { "failures": 0, "warnings": 0, "status": "HEALTHY" }
}

In mail-only mode, the checks object contains just the mail block and the top-level mode is "mail". In WHOIS-only mode, the checks object contains just the domain_registration block and the top-level mode is "whois". When mail checks are skipped with --skip-mail, the mail block is omitted. When individual mail checks are skipped with --mail-checks or --skip-mail-checks, only the enabled mail subchecks appear under checks.mail.

Run self-diagnostics for the binary and local environment. --doctor does not require a domain and checks the install path, detected installation method, current and latest versions, system time, config file, DNS resolution, outbound HTTPS, WHOIS connectivity, and mail DNS capabilities:

site-health --doctor

Example:

site-health doctor
──────────────────
Binary path:      /opt/homebrew/bin/site-health
Install method:   Homebrew
Current version:  0.16.1
Latest version:   0.16.1    (up to date)

Environment
───────────
System time:        OK  2026-08-27T12:34:56Z
Config file:        OK  not configured
                    /Users/alice/.config/site-health/config.json
DNS resolution:     OK  example.com → 93.184.216.34
Outbound HTTPS:     OK  https://detectportal.firefox.com/success.txt → 200 (success)
WHOIS lookup:       OK  whois.iana.org:43 reachable
Mail DNS (MX):      OK  1 record(s)
Mail DNS (SPF):     OK  record found
Mail DNS (DMARC):   OK  record found
Status: HEALTHY

The latest-version check uses the GitHub Releases API. If the network is unavailable or the API rate-limit is exceeded, the check reports the error gracefully without failing the whole command.

Web UI

Run a local web interface for managing projects, domains, and check history in the browser:

site-health web

The UI opens at http://localhost:8080 by default. Use --port to choose a different port:

site-health web --port 8081

Web UI features

  • Projects: organize checks into separate projects, each with its own domain list and session history.
  • Run checks: enter domains and run health checks with optional flags such as Skip redirect check.
  • Results table: see the latest status for each domain plus a trend of the last 5 checks.
  • Issue details: click any domain row to expand the issue list (FAIL, WARN, INFO).
  • Session history: every run is saved as a session; clear history with Clear history.

Data is stored locally in the platform-specific user config directory (e.g. ~/.config/site-health/web on Linux or ~/Library/Application Support/site-health/web on macOS).

Configuration

Set default behavior in a config file so you do not have to repeat flags for every run. The default config path follows the XDG Base Directory Specification:

$XDG_CONFIG_HOME/site-health/config.json

If XDG_CONFIG_HOME is unset, it falls back to:

~/.config/site-health/config.json

Use --config <path> to load a different file. A missing config file is silently ignored; a malformed file exits with an error.

Generate a starter config file with all supported settings:

site-health --init-config

This writes the sample file to the default config path. Use --config <path> to write it elsewhere. It will not overwrite an existing file.

Example config:

{
  "verbose": false,
  "skip_redirect": true,
  "skip_mail": false,
  "skip_llms_txt": false,
  "whois": false,
  "format": "json",
  "expected_hosts": [],
  "mail_checks": ["mx", "spf"],
  "skip_mail_checks": []
}

Supported settings:

SettingTypeMatching flag
verboseboolean--verbose
skip_redirectboolean--skip-redirect
skip_mailboolean--skip-mail
skip_llms_txtboolean--skip-llms-txt
whoisboolean--whois
formatstring--format
expected_hostsstring[]--expected-hosts
mail_checksstring[]--mail-checks
skip_mail_checksstring[]--skip-mail-checks

The same options can be set via environment variables:

export SITE_HEALTH_FORMAT=json
export SITE_HEALTH_SKIP_REDIRECT=true
export SITE_HEALTH_EXPECTED_HOSTS=example.com,www.example.com
export SITE_HEALTH_MAIL_CHECKS=mx,spf

Precedence, from highest to lowest:

  1. Explicit CLI flags
  2. Environment variables (SITE_HEALTH_*)
  3. Config file values
  4. Built-in defaults

When --verbose is enabled and a config file is loaded, the path is printed to stderr so it is clear where defaults are coming from.

Installation

Homebrew

Preferred installation method on macOS:

brew install atillalab/tap/site-health

Install with go install

go install github.com/atillalab/site-health@latest

Pre-built binary

Download the latest release for your platform from GitHub Releases.

Build from source

Clone the repository and build:

git clone https://github.com/atillalab/site-health.git
cd site-health
go build -o site-health .

The resulting binary has zero external dependencies.

Exit codes

  • 0 — healthy, no failures
  • 1 — one or more checks failed
  • 2 — usage error (missing domain, invalid flag, etc.)

Development

Run tests

go test ./...

Run tests with readable, per-test output:

go test ./... -v

Build

go build -o site-health .

Vet

go vet ./...

License

MIT

Contributors

atillalab

58 commits

atillalab/site-health

A fast CLI for checking website and domain health.

20

stars

58

commits

Go

primary language

Aug 29, 2026

updated

README

site-health

A fast CLI for checking website and domain health.

Status: Go rewrite complete (v0.16.1)

Quick Start

site-health example.com
site-health --verbose example.com
site-health --mail example.com
site-health --whois example.com
site-health --skip-mail example.com
site-health --mail-checks spf example.com
site-health --skip-redirect example.com
site-health --format json example.com
site-health --doctor
site-health --init-config
site-health web
site-health web --port 8081

Features

Zero external dependencies — stdlib only:

  • Domain registration expiry
  • Registrar lookup
  • Optional verbose output for troubleshooting
  • DNS resolution (A, AAAA, CNAME)
  • TCP connectivity (80/443)
  • HTTP/HTTPS availability
  • Redirect and canonical host validation
  • SSL certificate validation
  • Response time measurement
  • HTML content validation
  • Common server/PHP/WordPress error detection
  • Parked domain detection
  • Final summary with failure and warning counts
  • MX record lookup, including Null MX recognition
  • SPF TXT record validation
  • DMARC TXT record validation
  • Mail checks skippable in site mode with --skip-mail
  • Individual mail checks selectable with --mail-checks and --skip-mail-checks
  • WHOIS-only mode with --whois for domain registration checks without HTTP probes
  • Optional /llms.txt availability check (skippable with --skip-llms-txt)
  • Canonical redirect check skippable with --skip-redirect
  • Machine-readable JSON output for automation and monitoring
  • Config file and environment variables for default flags
  • Self-diagnostic --doctor mode for the binary and local environment
  • Local web UI for project-based checks and session history (site-health web)

Usage

Run the full website/domain health check. By default, output is a concise dashboard:

site-health example.com

Example:

Site Health Check
Domain: example.com
Expected Hosts: example.com

SITE HEALTH
───────────
● example.com
  DNS          OK
  HTTPS        OK
  SSL          81 days
  Domain Reg   757 days (14 Sep 2028)
  Redirect     OK
  Response     184 ms
  Mail         OK
Status: HEALTHY

When a forwarded or explicit canonical URL matters, the dashboard includes it:

Site Health Check
Domain: example.com
Expected Hosts: example.org

SITE HEALTH
───────────
● example.com
  DNS          OK
  HTTPS        OK
  SSL          81 days
  Domain Reg   757 days (14 Sep 2028)
  Redirect     OK
  Response     184 ms
  Mail         OK
Status: HEALTHY

Show detailed troubleshooting diagnostics instead of the dashboard:

site-health --verbose example.com

Run only mail-related DNS checks:

site-health --mail example.com

Mail mode checks only:

  • MX
  • SPF
  • DMARC

Example:

MAIL HEALTH
───────────
● example.com
  MX           OK
  SPF          OK
  DMARC        WARN
Status: WARNING

Show detailed mail diagnostics:

site-health --mail --verbose example.com

Run only WHOIS / domain-registration checks:

site-health --whois example.com

WHOIS mode checks only:

  • Domain registration expiry
  • Registrar

Example:

WHOIS / Domain Registration
─────────────────────────
● example.com
  Domain Reg   350 days (13 Aug 2027)
  Registrar    RESERVED-Internet Assigned Numbers Authority
Status: HEALTHY

Show detailed WHOIS diagnostics:

site-health --whois --verbose example.com

Run only selected mail checks:

site-health --mail-checks spf example.com
site-health --mail-checks mx,dmarc example.com
site-health --mail --mail-checks spf example.com

Skip selected mail checks:

site-health --skip-mail-checks spf example.com
site-health --mail --skip-mail-checks spf example.com

The supported mail check names are mx, spf, and dmarc. --mail-checks and --skip-mail-checks filter the mail portion of the current run. Use them with --mail for mail-only output, or without --mail for a full site health run with filtered mail checks. Use --skip-mail when you want a full site health run without mail checks.

Skip mail-related DNS checks in a full site health run:

site-health --skip-mail example.com

This skips MX, SPF, and DMARC checks when mail health is outside the monitoring scope. For domains you control that deliberately do not send or receive mail, explicit no-mail DNS policy is still preferred: Null MX, SPF -all, and DMARC p=reject.

Skip the optional /llms.txt check:

site-health --skip-llms-txt example.com

Skip the canonical redirect check when the site intentionally serves the same content from multiple URL variants (for example, both https://example.com and https://www.example.com):

site-health --skip-redirect example.com

This keeps HTTPS, response-time, and SSL checks running, but does not enforce a single canonical URL. Use it for domains where redirecting every variant to one URL is not desired.

Forwarded domains are detected automatically when the final URL is unambiguous:

site-health example.com

To strictly require a specific final host, provide it explicitly:

site-health --expected-hosts example.org example.com

When a site intentionally serves the same content from multiple hosts (for example, both https://example.com and https://www.example.com), pass them as a comma-separated list. The singular --expected-host is also accepted as an alias:

site-health --expected-hosts example.com,www.example.com example.com

Output a machine-readable JSON document instead of the dashboard (useful for scripts, CI, and monitoring). --verbose output is suppressed in JSON mode; the same exit codes apply (0 healthy, 1 issues found):

site-health --format json example.com

Example:

{
  "tool": "site-health",
  "version": "0.16.1",
  "domain": "example.com",
  "mode": "site",
  "expected_hosts": ["example.com"],
  "forwarding": {
    "auto_detected": false,
    "ambiguous": false,
    "candidates": []
  },
  "checks": {
    "dns": { "status": "OK", "a": ["104.20.23.154"], "aaaa": [] },
    "https": { "status": "OK" },
    "ssl": { "status": "OK", "days_remaining": 81, "subject": "CN=example.com" },
    "redirect": { "status": "OK" },
    "response": { "status": "OK", "ms": 184 },
    "domain_registration": {
      "status": "OK",
      "registrar": "MarkMonitor Inc.",
      "expires_at": "2028-09-14T04:00:00Z",
      "days_remaining": 757
    },
    "mail": {
      "status": "OK",
      "mx": { "status": "OK", "records": ["0 ."] },
      "spf": { "status": "OK", "records": ["v=spf1 -all"] },
      "dmarc": { "status": "OK", "records": ["v=DMARC1;p=reject"] }
    }
  },
  "issues": [],
  "summary": { "failures": 0, "warnings": 0, "status": "HEALTHY" }
}

In mail-only mode, the checks object contains just the mail block and the top-level mode is "mail". In WHOIS-only mode, the checks object contains just the domain_registration block and the top-level mode is "whois". When mail checks are skipped with --skip-mail, the mail block is omitted. When individual mail checks are skipped with --mail-checks or --skip-mail-checks, only the enabled mail subchecks appear under checks.mail.

Run self-diagnostics for the binary and local environment. --doctor does not require a domain and checks the install path, detected installation method, current and latest versions, system time, config file, DNS resolution, outbound HTTPS, WHOIS connectivity, and mail DNS capabilities:

site-health --doctor

Example:

site-health doctor
──────────────────
Binary path:      /opt/homebrew/bin/site-health
Install method:   Homebrew
Current version:  0.16.1
Latest version:   0.16.1    (up to date)

Environment
───────────
System time:        OK  2026-08-27T12:34:56Z
Config file:        OK  not configured
                    /Users/alice/.config/site-health/config.json
DNS resolution:     OK  example.com → 93.184.216.34
Outbound HTTPS:     OK  https://detectportal.firefox.com/success.txt → 200 (success)
WHOIS lookup:       OK  whois.iana.org:43 reachable
Mail DNS (MX):      OK  1 record(s)
Mail DNS (SPF):     OK  record found
Mail DNS (DMARC):   OK  record found
Status: HEALTHY

The latest-version check uses the GitHub Releases API. If the network is unavailable or the API rate-limit is exceeded, the check reports the error gracefully without failing the whole command.

Web UI

Run a local web interface for managing projects, domains, and check history in the browser:

site-health web

The UI opens at http://localhost:8080 by default. Use --port to choose a different port:

site-health web --port 8081

Web UI features

  • Projects: organize checks into separate projects, each with its own domain list and session history.
  • Run checks: enter domains and run health checks with optional flags such as Skip redirect check.
  • Results table: see the latest status for each domain plus a trend of the last 5 checks.
  • Issue details: click any domain row to expand the issue list (FAIL, WARN, INFO).
  • Session history: every run is saved as a session; clear history with Clear history.

Data is stored locally in the platform-specific user config directory (e.g. ~/.config/site-health/web on Linux or ~/Library/Application Support/site-health/web on macOS).

Configuration

Set default behavior in a config file so you do not have to repeat flags for every run. The default config path follows the XDG Base Directory Specification:

$XDG_CONFIG_HOME/site-health/config.json

If XDG_CONFIG_HOME is unset, it falls back to:

~/.config/site-health/config.json

Use --config <path> to load a different file. A missing config file is silently ignored; a malformed file exits with an error.

Generate a starter config file with all supported settings:

site-health --init-config

This writes the sample file to the default config path. Use --config <path> to write it elsewhere. It will not overwrite an existing file.

Example config:

{
  "verbose": false,
  "skip_redirect": true,
  "skip_mail": false,
  "skip_llms_txt": false,
  "whois": false,
  "format": "json",
  "expected_hosts": [],
  "mail_checks": ["mx", "spf"],
  "skip_mail_checks": []
}

Supported settings:

SettingTypeMatching flag
verboseboolean--verbose
skip_redirectboolean--skip-redirect
skip_mailboolean--skip-mail
skip_llms_txtboolean--skip-llms-txt
whoisboolean--whois
formatstring--format
expected_hostsstring[]--expected-hosts
mail_checksstring[]--mail-checks
skip_mail_checksstring[]--skip-mail-checks

The same options can be set via environment variables:

export SITE_HEALTH_FORMAT=json
export SITE_HEALTH_SKIP_REDIRECT=true
export SITE_HEALTH_EXPECTED_HOSTS=example.com,www.example.com
export SITE_HEALTH_MAIL_CHECKS=mx,spf

Precedence, from highest to lowest:

  1. Explicit CLI flags
  2. Environment variables (SITE_HEALTH_*)
  3. Config file values
  4. Built-in defaults

When --verbose is enabled and a config file is loaded, the path is printed to stderr so it is clear where defaults are coming from.

Installation

Homebrew

Preferred installation method on macOS:

brew install atillalab/tap/site-health

Install with go install

go install github.com/atillalab/site-health@latest

Pre-built binary

Download the latest release for your platform from GitHub Releases.

Build from source

Clone the repository and build:

git clone https://github.com/atillalab/site-health.git
cd site-health
go build -o site-health .

The resulting binary has zero external dependencies.

Exit codes

  • 0 — healthy, no failures
  • 1 — one or more checks failed
  • 2 — usage error (missing domain, invalid flag, etc.)

Development

Run tests

go test ./...

Run tests with readable, per-test output:

go test ./... -v

Build

go build -o site-health .

Vet

go vet ./...

License

MIT

Contributors

atillalab

58 commits

Languages

Go

83.7%

HTML

15.3%