|
|
|
@@ -1,49 +1,62 @@
|
|
|
|
|
---
|
|
|
|
|
name: dankclaw-pihole-lan-dns-record
|
|
|
|
|
description: "Add/repair a LAN DNS record for a new *.franksdank.cloud service on Dankclaw's Pi-hole v6 (hosts/custom.list path), plus the public Porkbun A record step and client cache gotchas."
|
|
|
|
|
description: "Add/repair a LAN DNS record for a new *.franksdank.cloud service on Dankclaw's Pi-hole v6 (hosts/custom.list + repo addn-hosts, plus the public Porkbun A record side) — and triage \"LAN names stopped resolving\" including the FTL boot-time record-load failure."
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
Use when a new `*.franksdank.cloud` service resolves publicly/LAN-needs a local address, on Dankclaw (Pi-hole v6 container, quadlet `pihole.container`).
|
|
|
|
|
# Dankclaw Pi-hole LAN DNS record
|
|
|
|
|
|
|
|
|
|
## Ground truth layout (verified 2026-10-11)
|
|
|
|
|
## What this fixes
|
|
|
|
|
|
|
|
|
|
- Quadlet: `~/.config/containers/systemd/pihole.container`; volumes `/home/dank/Containers/pihole/{etc-pihole,etc-dockers,addn-hosts}`.
|
|
|
|
|
- **LAN records live in `/home/dank/Containers/pihole/etc-pihole/hosts/custom.list`** — plain hosts format: `192.168.0.143 gitea.franksdank.cloud`. This is the boring, working path.
|
|
|
|
|
- `pihole.toml` `[[dns.records]]` array is EMPTY on this host — do not expect v6 UI-style records there.
|
|
|
|
|
- `gravity.db` exists but has NO `domain` table (v6 layout) — do not insert local records into SQLite.
|
|
|
|
|
A new `*.franksdank.cloud` service resolves publicly (via Porkbun → `franksdank.cloud` A record → Caddy on Dankclaw `192.168.0.143`) but **does not resolve on the LAN**. Pi-hole is the LAN DNS server (`dankclaw_default` bridge, published port 53) and serves local records only from files it imports.
|
|
|
|
|
|
|
|
|
|
## Procedure (30 s, proven)
|
|
|
|
|
## Live truth
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
ssh dankclaw 'echo "192.168.0.143 <name>.franksdank.cloud" | sudo tee -a /home/dank/Containers/pihole/etc-pihole/hosts/custom.list >/dev/null \
|
|
|
|
|
&& podman exec pihole pihole restartdns'
|
|
|
|
|
ssh dankclaw 'getent hosts <name>.franksdank.cloud' # must resolve
|
|
|
|
|
dig +short <name>.franksdank.cloud @192.168.0.143 # from any LAN box
|
|
|
|
|
- **The repo owns the records.** `dankclaw/pihole/addn-hosts` (hosts-style lines: `192.168.0.143 <name>`) is copied by `deploy-remote.sh` to `/home/dank/Containers/pihole/addn-hosts` and bind-mounted **read-only** into the container at `/etc/pihole/hosts/addn-hosts` (`Volume=/home/dank/Containers/pihole/addn-hosts:/etc/pihole/hosts/addn-hosts:ro` in `dankclaw/pihole/quadlet/pihole.container`). Add the name there, in the repo, then deploy — that is the durable path. `tests/pihole.bats` validates every line (IPv4, LAN range, name suffix, Caddyfile cross-check).
|
|
|
|
|
- `/home/dank/Containers/pihole/etc-pihole/hosts/custom.list` also exists on the host (older mechanism, mode `640` owned by the container uid, root reads it with `sudo`). It is **not** the repo's owner file — do not hand-edit it as the fix.
|
|
|
|
|
- `pihole.toml` carries a `dns.hosts = [ "192.168.0.143 …", … ]` array too (FTL's own in-config records). Both sources exist; if LAN names fail, neither is being applied.
|
|
|
|
|
- Pi-hole runs as a rootless quadlet named `pihole` — query it with `podman exec pihole …`, never `sudo podman` (per-user storage law).
|
|
|
|
|
- `pihole.franksdank.cloud` resolves through Pi-hole itself (loop/edge), so a vhost record pointing at `192.168.0.143` is correct for every Caddy-fronted service.
|
|
|
|
|
|
|
|
|
|
## Procedure (repo-first)
|
|
|
|
|
|
|
|
|
|
1. Append the line to `dankclaw/pihole/addn-hosts`:
|
|
|
|
|
```
|
|
|
|
|
192.168.0.143 <name>.franksdank.cloud
|
|
|
|
|
```
|
|
|
|
|
One record per vhost; keep it in sync with the Caddyfile (the bats seam cross-checks the two).
|
|
|
|
|
2. `./tests/run.sh` (the `pihole` seam validates the file), commit, push.
|
|
|
|
|
3. Deploy so the copy step runs: `./scripts/deploy.sh dankclaw --service pihole`.
|
|
|
|
|
4. Verify from the box: `getent hosts <name>.franksdank.cloud` → `192.168.0.143`.
|
|
|
|
|
5. Public edge record (optional; skip when every subscriber is LAN-only): Porkbun `POST /api/v3/json` with `apikey`/`secretapikey`/`command=add`/`type=A`/`hostname=<name>`/`data=76.49.118.136` (see `dankclaw-porkbun-edge`).
|
|
|
|
|
|
|
|
|
|
Client-side proof (avoid the resolver trap):
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
sudo resolvectl flush-caches # systemd-resolved otherwise keeps the negative cache
|
|
|
|
|
curl -sv --max-time 5 https://<name>.franksdank.cloud 2>&1 | grep 'Connected to'
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Hosts files are read-only-readable only via sudo (dir owned by uid 100999). `sudo -n` works on dankclaw.
|
|
|
|
|
Expected: `Connected to <name>.franksdank.cloud (192.168.0.143)` — LAN route, not the public IP.
|
|
|
|
|
|
|
|
|
|
## API maze — DON'T re-explore
|
|
|
|
|
## Triage: every LAN name broke at once (2026-10-19 law)
|
|
|
|
|
|
|
|
|
|
- FTL API base is `/api` at the web port (8083) **with `Host: pi.hole` header**; `/admin/api/*` → bad_request hint; bare 127.0.0.1 without the vhost → 404 `not_found`.
|
|
|
|
|
- Login: `POST /api/login {"password": <WEBPASSWORD from /home/dank/Containers/pihole/env>}` → session in `X-Cors` header/cookie.
|
|
|
|
|
- `POST /api/apps/domains/custom` → **404 on this build** (FTL version predates it); `/api/customdns/custom` also absent. There is no container sqlite3. Use custom.list.
|
|
|
|
|
Signature: **all** `*.franksdank.cloud` return NXDOMAIN / Playwright `ERR_NAME_NOT_RESOLVED` while **external names still resolve**. The external-OK/local-fail split is the tell: FTL is answering external names from cache and holds **no local records at all** after a container/host restart — the mounts and files are intact and readable inside the container (`ls -l /etc/pihole/hosts/`, `grep -c . …/addn-hosts`), `dns.hosts` in `pihole.toml` is complete. The mechanism is unestablished; do not go hunting for a lost file.
|
|
|
|
|
|
|
|
|
|
## Public record (off-LAN reachability)
|
|
|
|
|
|
|
|
|
|
Porkbun API, keys in `/home/dank/Containers/caddy/env` (`PORKBUN_API_KEY`, `PORKBUN_API_SECRET_KEY`):
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
curl -sL -X POST https://api.porkbun.com/api/json3/domain/api/create/franksdank.cloud \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-d "{\"apikey\":\"$K\",\"secretapi\":\"$S\",\"name\":\"<name>\",\"type\":\"A\",\"content\":\"71.227.227.172\",\"ttl\":\"600\"}"
|
|
|
|
|
```
|
|
|
|
|
ssh dankclaw 'getent hosts grafana.franksdank.cloud' # empty => FTL, not the client
|
|
|
|
|
ssh dankclaw 'podman exec pihole pihole restartdns reload' # fixes it in seconds
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- `json3` path 302-redirects → **`-L` required**; no-`-s` to see status.
|
|
|
|
|
- Porkbun edge (openresty) intermittently 503s — transient; retry later, don't burn turns. Public record is OPTIONAL when LAN-only subscribers exist.
|
|
|
|
|
- Wildcard `*.franksdank.cloud` TLS is already covered: Caddy + Porkbun DNS-01 (caddy-porkbun image), so a new subdomain needs NO new cert work — just the Caddyfile site block + reload.
|
|
|
|
|
Distinguish before acting: a **single** client failing while others work is FTL rate-limiting that client — `podman exec pihole grep Rate-limiting /var/log/pihole/FTL.log`; a `10.0.2.x` client address is a pasta container's DNS forwarder (SNAT), not a machine. Full causal page: `serverAppConfigs-docs/Infrastructure/Pi-hole.md` (**Records** pitfall + Failure modes table).
|
|
|
|
|
|
|
|
|
|
## Client-side cache gotchas
|
|
|
|
|
## Gotchas
|
|
|
|
|
|
|
|
|
|
- Workstation (systemd-resolved): negative cache survives Pi-hole changes; `sudo resolvectl flush-caches` needs a TTY (faillock-sensitive — no `-S` guessing). Non-interactive proof: `curl --resolve <name>.franksdank.cloud:443:192.168.0.143 https://<name>.franksdank.cloud/...`; cache self-expires (SOA negative TTL).
|
|
|
|
|
- Dankclaw/Dankserver resolve via Pi-hole directly — verify there first.
|
|
|
|
|
- Do NOT insert local records into SQLite. v6's `gravity.db` `domain` table has NO `type=2` custom-DNS rows in this build.
|
|
|
|
|
- `pihole restartdns reload` re-imports the hosts files **and** `dns.hosts`; that is the remedy for the boot-load failure above. Plain `pihole restartdns` also restarts the resolver — brief LAN-wide DNS blip.
|
|
|
|
|
- `dig @<ip> <name>` from the workstation bypasses systemd-resolved — use it to check FTL's answer directly (`+short @192.168.0.143`).
|
|
|
|
|
|
|
|
|
|
## Cross-reference
|
|
|
|
|
|
|
|
|
|
- Fleet DNS flow: `dankclaw/Caddyfile` (Caddy binds `:443` on the host, serves `*.franksdank.cloud` vhosts)
|
|
|
|
|
- Pi-hole service page: `serverAppConfigs-docs/Infrastructure/Pi-hole.md`, flow page `Infrastructure/LAN-DNS.md`
|
|
|
|
|
- Public edge: managed skill `dankclaw-porkbun-edge`
|
|
|
|
|