Hardening
A Nexus Telemetry Fleet server starts listening on its own host only, with no encryption of its own. TLS for the dashboard comes from a reverse proxy in front of the fleet server, or from the fleet server itself with a certificate it is given. See Install for installing a fleet server.
Reverse proxy
The production compose file runs Caddy on ports 80 and 443, and keeps the dashboard port inside the compose network, so only Caddy answers from outside. Caddy obtains the dashboard’s certificate by ACME at the first start and renews it. Any other reverse proxy can serve the dashboard port in Caddy’s place.
Collectors connect to the fleet server on port 9443, separately from the dashboard. The compose file publishes that port straight from the host. It must never pass through Caddy or any other proxy that terminates TLS.
Warning: at enrolment a collector records the fleet server’s own private certificate chain, and from then on it accepts that chain only. A collector that is offered a publicly trusted certificate on port 9443 refuses it and never connects.
Your own certificate
To have the fleet server terminate TLS itself, put the certificate chain and
its key where the service user can read them, set NF_DASHBOARD_TLS_CERT
and NF_DASHBOARD_TLS_KEY to their paths, and restart.
sudo systemctl restart nf-serverThe startup log then reads Web server listening (HTTPS).
Both variables are paths to PEM files, and both must be set. With only one
set, the dashboard stays on plain http://. Also set NF_SERVER_URL to the
dashboard’s https:// address, so that the enrolment commands the dashboard
generates use it. The fleet server does not reload a renewed certificate,
so restart the service after each renewal.
A fleet server that listens on an address other than loopback, with neither variable set, warns at startup that anyone who can reach the dashboard has full control of the fleet.
Forwarded proto header
Where a proxy terminates TLS and the fleet server itself stays on loopback,
set NF_TRUST_FORWARDED_PROTO=1. The fleet server then reads the proxy’s
X-Forwarded-Proto header and marks the session cookie Secure.
Never set it on a fleet server whose dashboard port is reachable directly. The header comes from the client and can be forged, and the fleet server does not check that a proxy is in front of it.
Health checks
3 addresses answer without a sign-in.
| Address | Answers | For |
|---|---|---|
GET /health |
200 while the process is running, whatever else is wrong | The orchestrator or container health check |
GET /ready |
200 only when the database is open and the fleet server is not shutting down. 503 otherwise | A load balancer, and a deployment waiting to send traffic |
GET /healthz |
200 with a small JSON body while the fleet server is healthy. 503 while it is degraded | Monitoring from another host |
curl -s https://<your domain>/healthzIn the JSON body, status reads ok with a 200. It reads degraded with a
503 in the 2 cases the fleet server calls degraded: its database stops
answering, or the hourly pass that summarises readings has not run for 3
hours. See Server health.
External probe
The monitor that calls /healthz belongs on a host outside the fleet
server’s network, so that it still runs when the fleet server or its network
is down. The External probe check on Server
health only confirms that /healthz
answers. It does not watch the fleet server from outside.
Logs and metrics
The fleet server writes its log to standard output, one JSON object per line,
at the level set by NF_LOG. The default is info. NF_LOG_FORMAT=pretty
writes readable lines instead of JSON.
sudo journalctl -u nf-server -fUnder Docker the same lines come from docker logs. The fleet server writes
no log file of its own.
GET /metrics answers in Prometheus format on the dashboard port. It gives
fleet-wide figures: collectors enrolled and online, the database size, user
sessions, certificate expiry times, and running totals of enrolments,
renewals and revocations. It gives no terminal telemetry. It answers only to
a request that sends NF_PROBE_TOKEN as a bearer token, and is not served
while that variable is unset. The full /healthz body requires the same token.
Rate limits
Each limit is a count per minute. Once it is reached, further attempts in that minute are refused with HTTP 429.
| Limit | Per minute | Variable |
|---|---|---|
| Enrolment attempts from one source address | 30 | NF_ENROL_MAX_PER_IP |
| Enrolment failures against one token | 20 | none |
| Enrolment failures across the fleet server | 100 | none |
| Sign-in failures from one address | 20 | none |
The enrolment count uses the X-Forwarded-For header, so a public fleet
server requires a proxy in front that sets that header from the real source
address. The sign-in count uses the peer address, and reads that header only
from a proxy on a loopback or private network address.
Dashboard access from other hosts
The dashboard listens on 127.0.0.1:3000 unless NF_LISTEN sets another
address, so by default only the host it runs on can reach it. Before opening
it to other hosts, put TLS or a proxy in front of it, and create the first
user, because until a user exists the dashboard lets anyone in. See
Install.
See Server configuration for every variable named here and its default.