Added an internet-independent local access path for all homelab services: a *.telep.lan wildcard DNS record on telep-router pointing every name at the mainframe, plus a Caddy v2 reverse proxy on telep-mainframe that maps stable *.telep.lan names to each backend. Home or away, internet or not, every service is reachable by a stable name; Tailscale remains for remote access.

Caddy is a single point of failure for ALL domain access — and it lost a boot-race for ~1.6 days

On 2026-08-17 this Caddy was found failed since the 2026-08-15 YubiKey reboots: it started before the LAN IP 192.168.1.123 was assigned and could not bind :443, taking down every *.telep.lan name AND both levandor.io portals by-domain — silently. Fixed with net.ipv4.ip_nonlocal_bind=1 + a restart drop-in. Full write-up below (Caddy boot-race outage (2026-08-17)); runbook caddy-boot-race.

Motivation

Tailscale-only exposure means services vanish when there is no internet (and some services were bound to 127.0.0.1 + tailscale serve only, so they had no LAN entry point at all). This adds a local, internet-independent path while keeping Tailscale for remote.

Local DNS — wildcard on telep-router

A wildcard address record was added to dnsmasq on telep-router so every *.telep.lan name resolves to the mainframe (192.168.1.123):

uci add_list dhcp.@dnsmasq[0].address='/telep.lan/192.168.1.123'
uci commit dhcp
/etc/init.d/dnsmasq restart

LAN clients pick this up automatically because the router is their DHCP-advertised DNS server. Verified: files.telep.lan, kraken.telep.lan, and arbitrary *.telep.lan names all resolve to .123.

AAAA is NXDOMAIN — this is cosmetic

The wildcard is an A-record only; AAAA lookups return NXDOMAIN. IPv6 is disabled on the LAN anyway (see IPv6 disabled on the LAN (2026-07-28)) so the A-record path is all that matters.

dnsmasq change — mind the duplicate-reservation footgun

Any dnsmasq edit on this router restarts the daemon. A bad config = site-wide DHCP+DNS outage. This change was made the same session as (and separate from) the duplicate dhcp-host outage — always verify dnsmasq restarts cleanly after committing.

Reverse proxy — Caddy on telep-mainframe

Caddy v2.11.4 installed from the official Caddy apt repo (cloudsmith caddyserver/stable).

The cloudsmith auto-config produced a broken repo URL on Debian trixie

The auto-generated config.deb.txt emitted an any-distro/any-version URL that 404’d on trixie. Correct the repo path to:

deb https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main
  • systemd unit + /etc/caddy/Caddyfile (original backed up as .orig).
  • Listens on *:80, with auto_https off so Caddy NEVER tries to obtain a Let’s Encrypt cert for the non-public .lan domain.
  • Left untouched: Tailscale serve (9 proxies) and all 7 docker containers. Caddy is purely additive.

Name → backend map

All entries are HTTP on :80, verified 200 end-to-end unless noted.

NameBackendNotes
telep.lan / home.telep.lan127.0.0.1:3010now the Homepage status dashboard (was inline HTML; old block backed up /etc/caddy/Caddyfile.bak-home-dash)
files.telep.lan127.0.0.1:8334filebrowser
frigate.telep.lanhttps://127.0.0.1:8971TLS backend, self-signed → tls_insecure_skip_verify
kraken.telep.lan192.168.1.200:8080the Pi — 502 while the Pi is offline, entry is correct
top.telep.lan127.0.0.1:8090top4-web / Top képek
print.telep.lan127.0.0.1:8095label printer editor
whiteboard.telep.lan127.0.0.1:8790tldraw board
ruview.telep.lan127.0.0.1:3000needs header_up Host {upstream_hostport} (backend 421’d otherwise)
go2rtc.telep.lan127.0.0.1:1984
jellyfin.telep.lan127.0.0.1:8096⚠️ guessed name, backend down — flagged for removal/rename

Two config gotchas worth remembering

  • frigate speaks HTTPS with a self-signed cert on :8971 → the upstream needs tls_insecure_skip_verify.
  • ruview returned HTTP 421 Misdirected Request until header_up Host {upstream_hostport} was added (its DNS-rebinding Host-header validation, same family of issue as its SENSING_ALLOWED_HOSTS check — see 2026-08-11-ruview-esp32-csi-real-hardware).

Deliberately NOT proxied

Not in tailscale serve and/or not browsable UIs: stirling-pdf (:8080), qdrant (:6333/:6334), knowledgebase (:8092), home-portal (:8093), ruview alt (:3001), frigate unauth (:5000).

Caddy boot-race outage (2026-08-17)

All *.telep.lan + both levandor.io portals were down by-domain for ~1.6 days

caddy.service had been failed since 2026-08-15 18:44 — since the YubiKey-FDE reboots. It went unnoticed because all that work was over console/ssh, never by domain.

Discovery. While wiring the home dashboard into Caddy, systemctl status caddy showed failed with:

listening on 192.168.1.123:443: bind: cannot assign requested address

Root cause. Caddy starts at boot before the LAN IP 192.168.1.123 is assigned to enp5s0, fails to bind :443, and does not retry — so it stayed dead. The bind 192.168.1.123 on the :443 blocks (needed to avoid colliding with Tailscale’s 100.115.209.87:443 — see 2026-08-15-admin-portal-passkey-olivetin) is exactly what makes it sensitive to the IP not being up yet.

Impact. Every *.telep.lan service and both levandor.io portals (admin.levandor.io, id.levandor.io) were unreachable-by-domain the whole time. Backends were fine; only the domain front door was gone.

Fix (applied).

  1. net.ipv4.ip_nonlocal_bind=1 — the real fix for the race; lets Caddy bind an address before it is assigned. Persisted in /etc/sysctl.d/99-caddy-nonlocal-bind.conf.
  2. systemd drop-in /etc/systemd/system/caddy.service.d/resilience.conf — belt-and-suspenders: Restart=on-failure, RestartSec=5, Wants=network-online.target, After=network-online.target.

After systemctl start caddy: home.telep.lan200, admin.levandor.io302. Also restarted oauth2-proxyadmin.levandor.io was 502 because that container was down too. Runbook: caddy-boot-race.

Result

Home or away, internet or not, every service is reachable by a stable *.telep.lan name. Tailscale remains the remote path.