Create dns-knot-pihole-end-to-end.md via n8n
This commit is contained in:
parent
78c9e7282c
commit
ae6b1de3be
116
Tech/Sessions/dns-knot-pihole-end-to-end.md
Normal file
116
Tech/Sessions/dns-knot-pihole-end-to-end.md
Normal file
@ -0,0 +1,116 @@
|
||||
---
|
||||
project: dns-knot-pihole-end-to-end
|
||||
type: session-notes
|
||||
status: completed
|
||||
path: Tech/Sessions
|
||||
tags:
|
||||
- homelab
|
||||
- dns
|
||||
- knot
|
||||
- pihole
|
||||
- openwrt
|
||||
- traefik
|
||||
created: 2026-05-08
|
||||
updated: 2026-05-08
|
||||
---
|
||||
# DNS — Knot + Pi-hole End-to-End
|
||||
|
||||
## Outcome
|
||||
|
||||
Phase 1 of the Traefik project closed. Internal DNS architecture from
|
||||
the homelab DNS decision doc is live: Knot DNS authoritative for
|
||||
`herbylab.dev` on LXC 103, Pi-hole conditionally forwarding the zone,
|
||||
OpenWrt passing answers through. All six initial records resolve
|
||||
cleanly from a normal LAN client through the full chain.
|
||||
|
||||
## Architecture (as built)
|
||||
|
||||
|
||||
Client → OpenWrt (10.0.11.1) → Pi-hole (10.0.11.50)
|
||||
├─ herbylab.dev → Knot (10.0.11.10)
|
||||
└─ everything else → Unbound → root
|
||||
|
||||
|
||||
## Records served
|
||||
|
||||
| Name | IP | VLAN |
|
||||
|---|---|---|
|
||||
| ns1 | 10.0.11.10 | Lab |
|
||||
| immich | 10.0.11.62 | Lab |
|
||||
| pihole | 10.0.11.50 | Lab |
|
||||
| plex | 10.0.11.54 | Lab |
|
||||
| pve | 10.0.21.188 | Private |
|
||||
| traefik | 10.0.21.181 | Private |
|
||||
|
||||
Migrated from `.lan` to `.dev` to enable LE wildcard via Cloudflare
|
||||
DNS-01 in Phase 2.
|
||||
|
||||
## Key Learnings
|
||||
|
||||
- **`knotc reload` does not re-bind sockets.** It reloads the config
|
||||
file but listening sockets only get re-evaluated on full daemon
|
||||
restart. If `listen:` directives change (or were missing on first
|
||||
start), `systemctl restart knot` is required. Symptom: zone loads,
|
||||
`zone-status` reports correctly, but `dig` returns "connection
|
||||
refused."
|
||||
- **Knot config order matters for references.** `acl` blocks must be
|
||||
defined before `zone` blocks that reference them — YAML validation is
|
||||
single-pass, no forward references. Same pattern likely applies to
|
||||
other ID-based references.
|
||||
- **Fresh PVE LXCs inherit Tailscale resolvers from the host.**
|
||||
`/etc/resolv.conf` gets populated with `100.100.100.100` by default.
|
||||
If the LXC isn't on the tailnet, name resolution silently fails until
|
||||
pointed at a reachable resolver. Permanent fix: configure DNS in the
|
||||
LXC's PVE config or, for a DNS server LXC, point it at itself once
|
||||
it's serving.
|
||||
- **OpenWrt rebind protection silently filters RFC1918 answers.** When
|
||||
dnsmasq has `rebind_protection='1'`, any DNS answer pointing to a
|
||||
private IP gets stripped — query returns NOERROR with ANSWER:0 and EDE
|
||||
15 (Blocked). The fix is whitelisting the domain via `rebind_domain`.
|
||||
Easy to miss because the block happens *after* the upstream answers
|
||||
correctly, so direct queries to Pi-hole or Knot work fine while
|
||||
client-path queries fail.
|
||||
- **EDE 15 (Blocked) doesn't always mean a blocklist match.** It's a
|
||||
generic "this answer was filtered" code. Pi-hole's blocklists,
|
||||
OpenWrt's rebind protection, and several other filters all use it.
|
||||
Pi-hole's query log saying "Allowed" while `dig` reports EDE 15 is the
|
||||
tell — block is happening downstream of Pi-hole.
|
||||
- **Pi-hole v6 renamed conditional forwarding.** It's now under
|
||||
reverse-server config with format
|
||||
`,,,`. Same plumbing, different
|
||||
UI surface.
|
||||
- **Direct-vs-chain queries are the diagnostic shortcut.** When a DNS
|
||||
chain fails, querying each link directly with `dig @`
|
||||
immediately localizes the broken hop. Saved real time tonight
|
||||
isolating the OpenWrt rebind issue.
|
||||
|
||||
## Decisions Locked
|
||||
|
||||
- Zone file lives at `/var/lib/knot/herbylab.dev.zone` on LXC 103,
|
||||
owned by `knot:knot`
|
||||
- Single NS record (`ns1`) for now; secondary will be added when NAS
|
||||
instance comes up
|
||||
- TTL strategy: 300 during buildout (current), raise to 3600 once stable
|
||||
- SOA serial format: `YYYYMMDDNN` (current: `2026050801`)
|
||||
- ACL allows transfer/notify from localhost only — will expand when
|
||||
secondary is added
|
||||
- Conditional forwarding scoped to `10.0.0.0/8` in Pi-hole —
|
||||
VLAN/firewall layer enforces actual access boundaries
|
||||
|
||||
## Open Items
|
||||
|
||||
- [ ] LXC `/etc/resolv.conf` is a manual edit pointing at Pi-hole —
|
||||
repoint at itself (10.0.11.10) with Pi-hole as fallback, make
|
||||
persistent
|
||||
- [ ] Knot zone file into git as source of truth
|
||||
- [ ] Ansible role for Knot primary deployment
|
||||
- [ ] Knot secondary on the NAS (after primary proven stable)
|
||||
- [ ] Second Pi-hole instance for redundancy
|
||||
- [ ] Pi-hole sync method decision (gravity-sync vs Teleporter)
|
||||
- [ ] Move Traefik VM to Lab VLAN (currently on Private from original
|
||||
bridge setup)
|
||||
- [ ] Raise TTLs to 3600 once buildout settles
|
||||
|
||||
## Next Session
|
||||
|
||||
Phase 2 — wildcard cert via Traefik + Cloudflare DNS-01. DNS layer is done.
|
||||
Loading…
Reference in New Issue
Block a user