DC-012: Add Kubernetes-style /healthz + /readyz probe aliases
Fresh users copy-pasting healthcheck blocks from k8s/Docker docs need
the standard short aliases. Without /healthz and /readyz they get
connection refused. This commit:
1. Adds /healthz + /readyz as root-level aliases for /health/live +
/health/ready in src/app.js. Handler bodies DRYed into named
functions (livenessHandler, readinessHandler) so a probe semantics
change updates all five paths at once.
2. Removes the dead /api/v1/health*, /api/v1/health/live, /api/v1/health/ready
registrations from PUBLIC_ROUTES and CSRF exclusion list — those
routes were never actually mounted on the apiRouter (only root
paths existed). Anyone probing /api/v1/health now gets a clean 404
instead of being routed through to a duplicate root handler.
3. Adds bypass for the 5 probe paths in three places where it matters:
- PUBLIC_ROUTES (no auth)
- csrf-protection.js excludedPaths (no CSRF check)
- middleware.js request-logging exclusion (k8s polling every 10s
doesn't flood the audit log)
- middleware.js Tailscale auth bypass (probes don't carry Tailscale
identity headers)
4. Adds __tests__/health-probe-aliases.test.js (19 tests):
- Alias equivalence (/healthz == /health/live, /readyz == /health/ready)
- Back-compat (/health == /health/live)
- Path consolidation (all 3 /api/v1/health* return 404)
- Source-of-truth PUBLIC_ROUTES allowlist sync check
- Source-of-truth src/app.js mount list sync check (catches drift
between handler mount and middleware allowlist)
5. Documents probes in README (copy-paste docker-compose.yml +
Kubernetes blocks) and user-guide (Health Probes section + System
API table updated).
Post-fix: 941/941 tests pass (+19 new). Zero new ESLint warnings
introduced. The pre-existing warnings/errors in src/app.js line 906
('os' is not defined) and the empty blocks in logging.test.js are
not regressions from this commit.
This commit is contained in:
@@ -98,6 +98,56 @@ status.yourdomain.com {
|
||||
6. **Access the dashboard**
|
||||
Open `https://status.yourdomain.com` in your browser
|
||||
|
||||
## Health Probes
|
||||
|
||||
DashCaddy exposes Kubernetes/Docker-standard health endpoints for container orchestration. **No auth required** — these are designed for orchestration tooling to poll.
|
||||
|
||||
| Path | Purpose | Returns |
|
||||
|------|---------|---------|
|
||||
| `/healthz` or `/health/live` | **Liveness** — is the Node.js process alive? | 200 with `{status: "alive", uptime: <seconds>}` |
|
||||
| `/readyz` or `/health/ready` | **Readiness** — are critical deps reachable? (config file, services file, Docker daemon, Caddy admin API) | 200 if all OK, 503 if any dep fails (with details in the `checks` object) |
|
||||
| `/health` | Backwards-compat alias for `/healthz` | Same as `/healthz` |
|
||||
|
||||
**When to use which:**
|
||||
- Use `/healthz` / `/health/live` in a `livenessProbe` — should the container be **restarted**?
|
||||
- Use `/readyz` / `/health/ready` in a `readinessProbe` — should traffic be **routed** to this instance?
|
||||
|
||||
### Docker Compose healthcheck
|
||||
|
||||
Copy-paste this into your DashCaddy `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
dashcaddy-api:
|
||||
image: ghcr.io/samiahmed7777/dashcaddy-api:latest
|
||||
# ... your existing config ...
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/readyz', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
```
|
||||
|
||||
### Kubernetes probes
|
||||
|
||||
```yaml
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 3001
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 3001
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
```
|
||||
|
||||
Both endpoints return JSON. Liveness is cheap (no I/O, no deps). Readiness touches the Docker daemon and Caddy admin API with a 3-second timeout each, so it's safe to poll every 10s without load concerns.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Reference in New Issue
Block a user