Docs/What the agent sends
What the agent sends
Before you helm install an agent inside your cluster, you
deserve to know exactly what crosses the wire. Here it is. Every
field, every endpoint, no surprises.
The agent's source is public:
github.com/statusharbor/lighthouse.
You can read the transmit code yourself in
internal/transport/
to verify everything below.
Network shape
- One destination:
https://lighthouse.statusharbor.io. The hostname is hardcoded at compile time. The agent never resolves any other host. - Outbound HTTPS only. No inbound ports, no UPnP, no reverse tunnels.
- Bearer-token auth on every request. The token is the one shown once in the dashboard when the Lighthouse is created. Lost? Mint a new one - old tokens stop working immediately.
- TLS-only. HTTP/1.1 + HTTP/2, modern cipher suites, no
fallback to HTTP. The hardcoded URL has the
https://scheme. - No third-party requests. The agent doesn't call analytics, telemetry, error reporting, or any other vendor.
Endpoints
The agent talks to five endpoints. Six, counting graceful shutdown.
POST /api/lighthouse/v1/register
Called once on agent start. Body:
{
"agent_version": "1.4.2",
"agent_hostname": "prod-01"
}That's the entire payload. The hostname is captured from
os.Hostname() (or container hostname inside Docker / k8s); we
use it as the display label until you set one in the UI.
The response contains your Lighthouse's ID, paused state, heartbeat interval, flap protection threshold, and the list of checks the agent should run.
POST /api/lighthouse/v1/heartbeat
Called every 60 seconds (configurable in admin config; default 60s). Body:
{
"agent_version": "1.4.2",
"config_etag": "etag-abc123",
"check_latencies": {
"<check-uuid>": {
"last_observed_latency_ms": 78,
"last_observed_at": "2026-05-09T16:00:00Z"
}
}
}agent_version- for your visibility in the dashboard ("Update available" hints).config_etag- the agent's cached config tag. If it doesn't match the server's, the response includes a fresh check list.check_latencies- sparse map of recent latency observations keyed by check UUID. Only round-trip times, no payload, no response bodies, no headers.
POST /api/lighthouse/v1/events
Called when a check changes state (passing → failing or vice versa). Body:
{
"sync_kind": "ongoing",
"events": [
{
"check_id": "<uuid>",
"prev_state": "ok",
"new_state": "down",
"response_time_ms": 320,
"status_code": 503,
"error_message": "expected status 200, got 503",
"agent_observed_at": "2026-05-09T16:00:14Z"
}
]
}prev_state/new_state- pass/fail strings.response_time_ms- total round-trip the agent observed.status_code- HTTP status, if applicable.error_message- humanized error string. For HTTP checks: status mismatches, keyword mismatches, header mismatches, TLS/handshake errors, DNS errors, timeouts. The agent does not transmit response bodies, custom headers, or any data the probed service emits beyond the assertion outcome.agent_observed_at- RFC3339 timestamp from the agent.
POST /api/lighthouse/v1/discoveries
Sent only if Kubernetes auto-discovery is enabled
(discovery.enabled = true in the Helm values). The agent watches
Ingress and Service resources in the namespaces you allowed
and posts a snapshot. Each entry is metadata only:
{
"discoveries": [
{
"kind": "ingress",
"namespace": "prod",
"resource_name": "web",
"host": "app.example.com",
"path": "/",
"port": 443,
"protocol": "https"
}
]
}The agent never sends pod logs, secrets, environment variables, configmaps, or anything other than the discovery metadata listed above. Discovery is opt-in; if you don't enable it, nothing ships.
POST /api/lighthouse/v1/host-metrics
Called on the host-metrics push interval whenever the metrics
collector is running. Body is a snappy-compressed Prometheus
remote-write protobuf batch carrying only the aggregate counters
derived from /proc and (on Kubernetes) the kubelet stats
endpoint - the same metric names listed on the
Host & cluster metrics page (e.g.
cpu_busy_percent, mem_used_bytes, disk_used_percent,
net_*_bytes_total).
Identifying labels are host (the agent-supplied hostname) and
lighthouse_id. Per-metric labels (mount point, network
interface, node name on Kubernetes) are included only where the
underlying metric needs them to be distinguishable. No process
lists, no command lines, no environment variables, no file
contents, no per-PID data. If the metrics relay is not
configured server-side, the endpoint returns 503 and the collector
backs off.
POST /api/lighthouse/v1/db-snapshots
Sent per registered database cluster on its collection cadence when
database monitoring is enabled. The agent connects
to your Postgres or MySQL from inside the network - using the
connection string the console delivers to the agent (stored
encrypted at rest, sealed to the agent's key on the wire for
single-agent installs) - introspects the read-only stat views, and
ships normalized facts: per-node identity and role, reachability,
connection counts, cache / buffer-pool hit ratio, deadlocks,
transaction-wraparound headroom, replication lag, and a hash + values
of the configuration settings. Only while you run an on-demand
Live update session does it also ship the top-N normalized
slow-query digests from pg_stat_statements / performance_schema.
It never sends raw table rows, the values your queries return, or the data in your database. All analysis - the config audit, thresholds, fitness verdict - happens server-side; the agent stays "run the read-only query, return the numbers". The connection string travels one way, to the agent, and stays in its memory; nothing about it is echoed back.
POST /api/lighthouse/v1/shutdown
Best-effort, sent on graceful shutdown (SIGTERM). Empty body. Lets the dashboard distinguish "agent stopped on purpose" from "agent died." If the request fails the agent doesn't retry - shutdown proceeds either way.
What the agent does not send
Explicitly, none of this leaves your network:
- HTTP response bodies from the services the agent probes.
- Request bodies (POST/PUT/PATCH bodies you configure on a monitor are stored in the dashboard, not echoed back through the agent).
- Response headers beyond the pass/fail outcome of
expected headersrules. - TLS certificate chains beyond expiry-day calculations.
- DNS query results beyond the assertion outcome.
- Pod logs, ConfigMaps, Secrets, Events, Deployments, or any other Kubernetes resource outside the Ingress / Service metadata listed above.
- Process lists, environment variables, command lines or any
per-PID data from
/proc. The host-metrics collector reads only the aggregate files (/proc/stat,/proc/meminfo,/proc/diskstats,/proc/net/devand friends) to derive the counters listed on the Host & cluster metrics page; nothing per-process leaves the host. - Files from disk beyond the agent's own config and event
buffer at
/var/lib/lighthouse. - Raw database rows, query results or the data in your database. Database introspection reads only the read-only stat views and ships normalized facts (counts, ratios, settings, and - during a Live update session - normalized slow-query digests); the values your queries return never leave the network.
- Database connection strings. The DSN is delivered to the agent and held only in memory; nothing about it is sent back to the console.
Buffering during outages
The agent maintains an on-disk event buffer at
/var/lib/lighthouse (override with LIGHTHOUSE_DATA_DIR). Today
the buffer is flushed on graceful shutdown - when the agent
receives SIGTERM it drains pending events to Status Harbor before
exiting, so a planned restart doesn't lose state.
Transient send failures during normal operation are not
buffered today; an event that fails to ship is logged and dropped.
On the next state change the agent emits the new value as usual,
so the dashboard converges as soon as the network recovers - but
the brief gap between "old state failed to send" and "new state
sends successfully" can land in a recovery resync rather than as
a real-time transition. Wiring the buffer into the runtime path
is on the roadmap.
Heartbeats and discoveries are best-effort by design - the most recent value is always re-derived on the next call, so there's nothing to buffer.
Verifying
The numbered claims above match the wire types in the agent's
internal/transport/
package. To audit the actual bytes:
# 1. Read the source.
git clone https://github.com/statusharbor/lighthouse
grep -r "json:" lighthouse/internal/transport/
# 2. Run with debug logging - prints request bodies before sending.
LIGHTHOUSE_LOG_LEVEL=debug ./lighthouse run
# 3. Or capture traffic at the network layer.
mitmproxy --mode reverse:https://lighthouse.statusharbor.ioContainer images on ghcr.io/statusharbor/lighthouse are signed
with cosign + Sigstore. Verify provenance before pulling:
cosign verify ghcr.io/statusharbor/lighthouse:latest \
--certificate-identity-regexp 'https://github.com/statusharbor/lighthouse/.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'