Public names are proxied CNAMEs to the Cloudflare Tunnel since #156 and work from the LAN, so Pi-hole's zone wildcard goes away. It now answers an explicit list; everything else is forwarded and resolves to Cloudflare from the LAN as from anywhere.
LAN-only, derived from every controller: none HTTPRoute; no public record and the tunnel 404s them
gitea, nextcloud
${GATEWAY_VIP}
Off Cloudflare's 100 MB / 100 s limits
keycloak, auth
${GATEWAY_VIP}
OIDC stays on one path for the LAN-path apps
unifi / crafty-mc / pihole-dns / plex-vip
their own VIPs
L4 / the resolver itself / Plex's certificate domain
Not listed, so Cloudflare from the LAN: the apex, grafana, crafty, seerr.
Rollout / LAN DNS blip. The env change rolls the StatefulSet (RollingUpdate, one pod at a time, pihole-1 then pihole-0; 2 replicas). No total outage expected: one replica answers throughout. Each replacement can lose a few UDP queries for ~1-2 s (clients retry), and for ~30-60 s the two pods answer differently for the unlisted names (both answers work). Estimate from the last measured rollout; not observed for this change.
Consequences to accept
The apex, grafana, crafty and seerr now depend on the internet and the tunnel from the LAN too. Add grafana to the list if it must survive an internet outage.
Rolling the tunnel back to wan. now also requires restoring the wildcard (recorded in runbooks/cloudflare-tunnel.md).
Flagged, not changed: the pihole container has no readiness probe; only the oauth2-proxy sidecar does, so Ready says nothing about DNS.
New L0 checkpihole-lan-names (whole-repo scope): no zone-wide entry; every disowned route, every tunnel-404 host and gitea/nextcloud covered, L4 names on their own VIPs. 10 mutants against the real files each failed the check.
Also corrects docs that still described public names as CNAME to wan., and the cloudflared entrypoint comment (the pinned image's Entrypoint is cloudflared, Cmd version).
Gate: local toolbox rc 3. Stages that did not run: gitea-settings (needs the CI token); L2/L3 conformance scaffold-skipped (no cluster). spec-immutability, decisions-log, lint, l0, render-golden, l1 passed; approval-policy reports N/A offline.
Needs /approve-override from the operator:conformance/tests/l0-static/pihole-lan-names/{check.sh,chainsaw-test.yaml} are sensitive paths, so approval-policy will be red in CI until then.
Not verified: behaviour against a live Pi-hole with the new list. After reconcile, dig @192.168.2.23 one name per row and confirm grafana returns Cloudflare. Details: decisions/2026-11-09-pihole-explicit-lan-names.md.
Public names are proxied CNAMEs to the Cloudflare Tunnel since #156 and work from the LAN, so Pi-hole's zone wildcard goes away. It now answers an explicit list; everything else is forwarded and resolves to Cloudflare from the LAN as from anywhere.
| Name (`.${BASE_DOMAIN}`) | Answer | Why |
|---|---|---|
| jackett, pihole, plex, qbittorrent, radarr, semaphore, sonarr, headlamp | `${GATEWAY_VIP}` | LAN-only, derived from every `controller: none` HTTPRoute; no public record and the tunnel 404s them |
| gitea, nextcloud | `${GATEWAY_VIP}` | Off Cloudflare's 100 MB / 100 s limits |
| keycloak, auth | `${GATEWAY_VIP}` | OIDC stays on one path for the LAN-path apps |
| unifi / crafty-mc / pihole-dns / plex-vip | their own VIPs | L4 / the resolver itself / Plex's certificate domain |
Not listed, so Cloudflare from the LAN: the apex, grafana, crafty, seerr.
**Rollout / LAN DNS blip.** The env change rolls the StatefulSet (RollingUpdate, one pod at a time, pihole-1 then pihole-0; 2 replicas). No total outage expected: one replica answers throughout. Each replacement can lose a few UDP queries for ~1-2 s (clients retry), and for ~30-60 s the two pods answer differently for the unlisted names (both answers work). Estimate from the last measured rollout; not observed for this change.
**Consequences to accept**
- The apex, grafana, crafty and seerr now depend on the internet and the tunnel from the LAN too. Add grafana to the list if it must survive an internet outage.
- Rolling the tunnel back to `wan.` now also requires restoring the wildcard (recorded in `runbooks/cloudflare-tunnel.md`).
**Flagged, not changed:** the `pihole` container has no readiness probe; only the `oauth2-proxy` sidecar does, so Ready says nothing about DNS.
**New L0 check** `pihole-lan-names` (whole-repo scope): no zone-wide entry; every disowned route, every tunnel-404 host and gitea/nextcloud covered, L4 names on their own VIPs. 10 mutants against the real files each failed the check.
Also corrects docs that still described public names as CNAME to `wan.`, and the cloudflared entrypoint comment (the pinned image's Entrypoint is `cloudflared`, Cmd `version`).
**Gate:** local toolbox rc 3. Stages that did not run: `gitea-settings` (needs the CI token); L2/L3 `conformance` scaffold-skipped (no cluster). spec-immutability, decisions-log, lint, l0, render-golden, l1 passed; approval-policy reports N/A offline.
**Needs `/approve-override` from the operator:** `conformance/tests/l0-static/pihole-lan-names/{check.sh,chainsaw-test.yaml}` are sensitive paths, so `approval-policy` will be red in CI until then.
**Not verified:** behaviour against a live Pi-hole with the new list. After reconcile, `dig @192.168.2.23` one name per row and confirm grafana returns Cloudflare. Details: `decisions/2026-11-09-pihole-explicit-lan-names.md`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Public names are proxied CNAMEs to the Cloudflare Tunnel since PR #156 and
work from the LAN, so they should resolve publicly there too. Replace the
address=/${BASE_DOMAIN}/ wildcard with explicit entries: the LAN-only names
(derived from every controller:none HTTPRoute), gitea/nextcloud (off
Cloudflare's 100 MB / 100 s limits), keycloak/auth, and the L4 VIPs.
Add L0 check pihole-lan-names, mutation-tested. Correct docs that still
described public names as CNAME to wan. and the cloudflared entrypoint comment.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Public names are proxied CNAMEs to the Cloudflare Tunnel since #156 and work from the LAN, so Pi-hole's zone wildcard goes away. It now answers an explicit list; everything else is forwarded and resolves to Cloudflare from the LAN as from anywhere.
.${BASE_DOMAIN})${GATEWAY_VIP}controller: noneHTTPRoute; no public record and the tunnel 404s them${GATEWAY_VIP}${GATEWAY_VIP}Not listed, so Cloudflare from the LAN: the apex, grafana, crafty, seerr.
Rollout / LAN DNS blip. The env change rolls the StatefulSet (RollingUpdate, one pod at a time, pihole-1 then pihole-0; 2 replicas). No total outage expected: one replica answers throughout. Each replacement can lose a few UDP queries for ~1-2 s (clients retry), and for ~30-60 s the two pods answer differently for the unlisted names (both answers work). Estimate from the last measured rollout; not observed for this change.
Consequences to accept
wan.now also requires restoring the wildcard (recorded inrunbooks/cloudflare-tunnel.md).Flagged, not changed: the
piholecontainer has no readiness probe; only theoauth2-proxysidecar does, so Ready says nothing about DNS.New L0 check
pihole-lan-names(whole-repo scope): no zone-wide entry; every disowned route, every tunnel-404 host and gitea/nextcloud covered, L4 names on their own VIPs. 10 mutants against the real files each failed the check.Also corrects docs that still described public names as CNAME to
wan., and the cloudflared entrypoint comment (the pinned image's Entrypoint iscloudflared, Cmdversion).Gate: local toolbox rc 3. Stages that did not run:
gitea-settings(needs the CI token); L2/L3conformancescaffold-skipped (no cluster). spec-immutability, decisions-log, lint, l0, render-golden, l1 passed; approval-policy reports N/A offline.Needs
/approve-overridefrom the operator:conformance/tests/l0-static/pihole-lan-names/{check.sh,chainsaw-test.yaml}are sensitive paths, soapproval-policywill be red in CI until then.Not verified: behaviour against a live Pi-hole with the new list. After reconcile,
dig @192.168.2.23one name per row and confirm grafana returns Cloudflare. Details:decisions/2026-11-09-pihole-explicit-lan-names.md.🤖 Generated with Claude Code