Files
HealthLog/docs/integrations/nightscout.md
T
Marc-André Bombeck 94bed12edc fix(egress): keep loopback grantable under an exact operator origin
A Nightscout self-host on host networking with
NIGHTSCOUT_PRIVATE_ORIGINS=http://localhost:1337 worked before and must
keep working unchanged; an operator who lists an exact loopback origin
with its port has made the same deliberate decision as one who lists a
LAN origin. The never-grantable floor is now the unspecified address,
link-local and the metadata endpoint only. Loopback (127/8, ::1,
localhost) is grantable when listed exactly, still resolved and pinned
at connect time with redirects forbidden, and still refused when not
listed.

::1 is answered before the embedded-IPv4 unwrap, which read it as the
IPv4-compatible spelling of 0.0.0.1 and refused it as unspecified. The
pinned Nightscout transport test runs the real floor again. Each refused
range keeps its own test; loopback moves to the grantable-when-listed
set with a test that an unlisted loopback is still refused, and a
Nightscout grant of http://localhost:1337 is asserted to parse.

Refs #947
2026-09-10 19:08:04 +02:00

93 lines
3.8 KiB
Markdown

# Nightscout integration
HealthLog can pull continuous-glucose readings from a Nightscout instance.
Public Nightscout origins work without an allowlist. Access to a private or
local destination is an operator decision and is denied unless its exact
origin is listed in `NIGHTSCOUT_PRIVATE_ORIGINS`.
## Security change for upgrades
`NIGHTSCOUT_PRIVATE_ORIGINS` is a breaking security boundary. The old
per-user “allow private host” opt-in is compatibility metadata only: it no
longer grants private-network access. Existing private connections that are
not operator-approved stop syncing with the stable
`private_origin_not_approved` reason until the operator configures the exact
origin.
Set a comma-separated list of complete origins:
```env
NIGHTSCOUT_PRIVATE_ORIGINS="https://cgm.internal.example:443,http://10.20.30.40:1337"
```
Each entry is an exact normalized `scheme://host:port` trust unit:
- only `http` and `https` are accepted;
- scheme, hostname, and effective port must all match;
- paths, query strings, fragments, embedded credentials, and wildcards are
rejected;
- approving one hostname does not approve subdomains, sibling hosts, or a
different port; and
- the unspecified address, link-local and the cloud-metadata range cannot
be listed, and a listed name that resolves there is refused at connect
time; loopback (`http://localhost:1337`, `http://127.0.0.1:1337`) stays a
valid grant for a host-networking deployment, exactly as before; and
- any malformed non-empty entry fails evaluation instead of silently
weakening the configured policy.
The grammar is shared with `NOTIFICATION_PRIVATE_ORIGINS`, the same grant
for webhook and ntfy targets (`docs/self-hosting/notifications.md`).
Do not put a Nightscout API token, capability URL, health data, or a URL
containing credentials in the allowlist. Restart the application after
changing the environment.
## Connect safely
Open **Settings → Integrations → Nightscout** and enter the instance base URL
and, when required, its Nightscout API token. HealthLog stores the connection
credentials encrypted. A public, read-only Nightscout instance can omit the
token.
For a private instance, configure the operator allowlist first and enter the
same origin in Settings. For example, if the allowlist contains
`https://cgm.internal.example:443`, these are not equivalent and remain
blocked:
```text
http://cgm.internal.example:443
https://cgm.internal.example:8443
https://other.cgm.internal.example:443
```
The user-controlled private-host checkbox or request field cannot override
this decision.
## DNS pinning and redirects
Every outbound request re-evaluates the stored origin against current server
policy. For public destinations, HealthLog resolves the hostname, rejects
private and embedded-private IPv4/IPv6 answers, and pins the approved address
for the connection so DNS cannot change between validation and use. Redirects
are validated and pinned again; a public URL cannot redirect into the local
network.
An exact private origin is intentionally allowed to resolve privately only
because the operator named that complete origin. Removing it from
`NIGHTSCOUT_PRIVATE_ORIGINS` takes authority away on the next fetch even if an
older user preference remains stored.
## Upgrade checklist
1. Inventory private Nightscout connections without copying their tokens into
tickets or logs.
2. Add only the exact origins that HealthLog must reach.
3. Restart HealthLog so the environment is reloaded.
4. Test the connection from Settings and confirm a sync succeeds.
5. Remove obsolete origins promptly; do not use a broad DNS suffix or wildcard
as a substitute for explicit entries.
If a previously working private connection reports that operator action is
required, compare its exact scheme, host, and port with the allowlist. Do not
restore access by changing the user's legacy opt-in.