Fast, concurrent endpoint health checker with rich terminal output.
Checks HTTP status, response time, TLS certificate expiry, and DNS resolution in parallel. Designed for operators who need a quick "is everything up?" check across a fleet of services.
npm install -g siteprobeOr run directly with npx:
npx siteprobe check https://example.com# Check one endpoint
siteprobe check https://example.com
# Check multiple (concurrent)
siteprobe check https://api.example.com https://db.example.com https://cdn.example.com
# JSON output for scripting
siteprobe check --json https://example.com
# Custom timeout and concurrency
siteprobe check --timeout 10000 --concurrency 20 [urls...]
# From a config file
siteprobe check --config ./siteprobe.jsonA YAML or JSON file with a targets array. The format is detected by extension
(.yaml/.yml → YAML, .json → JSON; other extensions are parsed as YAML,
which is a JSON superset).
{
"targets": [
"https://example.com",
"https://api.example.com:8080/health",
"https://internal.example.com"
]
}# siteprobe.yaml
targets:
- https://example.com
- https://api.example.com:8080/health
- https://internal.example.comBy default siteprobe blocks targets that resolve to loopback, private
(RFC1918 / unique-local), link-local (including the cloud-metadata address
169.254.169.254), or other reserved ranges, and reports them with
errorCategory: 'blocked'. This prevents siteprobe from being used as an SSRF
primitive when target lists come from untrusted config.
To deliberately probe internal endpoints, opt in:
# Allow loopback (127.0.0.0/8, ::1)
siteprobe check --allow-local http://localhost:8080/health
# Allow private + link-local + loopback
siteprobe check --allow-private http://10.0.0.5/healthThe guard validates the resolved IP (not just the hostname) and pins the connection to it, defending against DNS rebinding. It is re-applied on every redirect hop.
TTY mode with glyphs:
✓ https://example.com 122ms HTTP 200 · TLS valid (75d)
✓ https://api.example.com 101ms HTTP 200 · TLS valid (47d)
✗ https://broken.example.com 5000ms timeout
2/3 ok · 5.1s total
CI/pipe mode (ASCII, no color):
[ ok ] https://example.com 122ms HTTP 200 · TLS valid (75d)
[ ok ] https://api.example.com 101ms HTTP 200 · TLS valid (47d)
[FAIL ] https://broken.example.com 5000ms timeout
2/3 ok · 5.1s total
0— all probes succeeded1— one or more probes failed2— usage error (bad flags, no targets)
Use in scripts and CI:
siteprobe check --config ./endpoints.json || {
echo "One or more endpoints down" >&2
exit 1
}import { probe, runBatch } from 'siteprobe';
// Single probe
const result = await probe('https://example.com', {
timeoutMs: 5000,
tlsWarnDays: 30,
});
console.log(result.ok, result.httpStatus, result.tls?.daysUntilExpiry);
// Batch with concurrency
const batch = await runBatch(['https://a.com', 'https://b.com'], {
concurrency: 10,
onProgress: (r, done, total) => {
process.stdout.write(`[${done}/${total}] ${r.target}: ${r.ok ? 'ok' : 'fail'}\n`);
},
});
console.log(`${batch.okCount}/${batch.results.length} ok in ${batch.totalDurationMs}ms`);| Flag | Default | Description |
|---|---|---|
--timeout <ms> |
5000 | Per-probe timeout in milliseconds |
--concurrency <n> |
10 | Maximum concurrent probes |
--tls-warn-days <n> |
30 | Warn if TLS cert expires within N days |
--method <GET|HEAD> |
GET | HTTP method |
--expect <code> |
200-399 | Expected HTTP status code |
--allow-local |
false | Allow probing loopback addresses (SSRF opt-in) |
--allow-private |
false | Allow probing private/link-local/loopback addresses (SSRF opt-in; implies --allow-local) |
--no-follow-redirects |
false | Do not follow HTTP 3xx redirects |
--max-redirects <n> |
5 | Maximum redirect hops to follow |
--json |
false | Output as JSON |
--no-color |
false | Disable ANSI colors |
NO_COLOR— disables color output (standard convention)
For each target:
- DNS resolution — can we resolve the hostname? How many addresses?
- HTTP status — did the server respond with the expected code?
- Response time — total wall-clock probe duration in milliseconds
- TLS certificate — valid? When does it expire? (warns if within
--tls-warn-days) - Error category — structured classification:
timeout,dns_failure,connection_refused,tls_expired,http_error,blocked,too_many_redirects,unknown
- Lean dependencies — pure Node.js stdlib (dns, https) for probing; one small dependency (
yaml) for config parsing. No npm bloat. - Fast — bounded concurrency, per-probe timeouts, no sequential waiting.
- Structured output — JSON mode for scripting; glyph/ASCII auto-detection.
- Honest errors — categorized, not just string-matched.
- Small — about 500 lines including tests.
MIT