Files
serverAppConfigs/docs/Infrastructure/Pi-hole.md
T
Frank 0f59316be9 docs: Pi-hole KB page + dnsmasq retirement across the vault
- new docs/Infrastructure/Pi-hole.md (quadlet, records, upstream, web UI,
  failure modes incl. the rootless /etc/hosts single-label echo)
- LAN-DNS.md: Pi-hole quadlet section, router hand-off, host DNS
- Network Architecture / Caddy / Homepage / index / AGENTS.md: name swap
2026-08-24 13:54:35 -07:00

64 lines
4.0 KiB
Markdown

# Pi-hole
Pi-hole is the LAN DNS server for the homelab. It runs as a quadlet container on Dankclaw (192.168.0.143). It answers the flat `franksdank.cloud` / `franksdank.casa` service names and filters ad traffic on the LAN. It retired the dnsmasq quadlet on 2026-08-24. See [[LAN-DNS]] for the name-resolution flow and the router hand-off.
## Components
| Component | Where | Role |
|-----------|-------|------|
| `pihole` quadlet | `dankclaw/pihole/quadlet/pihole.container` | Boot-persistent container unit |
| FTL | `docker.io/pihole/pihole:latest` | DNS engine (a dnsmasq fork) + ad blocking |
| `addn-hosts` | `dankclaw/pihole/addn-hosts` | One A record per Caddy vhost |
| env file | `/home/dank/Containers/pihole/env` (host) | `ServerIP`, `TZ`, `DNS1`, `DNS2`, `WEBPASSWORD` |
| Web UI | `pihole.franksdank.cloud` (Caddy → 8083) | Dashboard + admin, family login |
## Quadlet
- **Install path on Dankclaw:** `~/.config/containers/systemd/pihole.container` (unit `pihole.service`)
- **Network:** `slirp4netns` (the same pattern as open-webui and gitea)
- **Published ports:** 53/udp + 53/tcp (DNS), 8083/tcp (web UI)
- **Mounts:**
- `/home/dank/Containers/pihole/etc-pihole` → `/etc/pihole` (config + state, preserved across restarts)
- `/home/dank/Containers/pihole/etc-dockers` → `/etc/dockers` (blocklists)
- `/home/dank/Containers/pihole/addn-hosts` → `/etc/dnsmasq.d/addn-hosts` (read-only; the record file from this repo)
- **Restart:** `Restart=always`, `RestartSec=5`
- **Deploy:** `./scripts/deploy-pihole-quadlet.sh dankclaw` (idempotent; preserves the data dirs)
## Records
The quadlet mounts `dankclaw/pihole/addn-hosts` into the container's dnsmasq config dir. FTL reads it and answers one A record per Caddy vhost, all pointing at `192.168.0.143`. The file stays in sync with the Caddyfile (`tests/pihole.bats` cross-checks the two). Add a name there and in Porkbun, then deploy. See [[LAN-DNS]] for the two-place rule.
## Upstream
The slirp netns has no useful `resolv.conf`. The env file pins the upstreams: `DNS1=1.1.1.1`, `DNS2=1.0.0.1` (mirrors the retired `dnsmasq.conf` `server=` lines). Every query that is not a local record goes to those resolvers. The zone apex and unknown subdomains fall through to Porkbun.
## Web UI and API
- **URL:** `https://pihole.franksdank.cloud/` (Caddy vhost, family basicauth → 8083)
- **Password:** `WEBPASSWORD` in the env file (the shared family password, the same credential as `CADDY_BASICAUTH_HASH`)
- **API:** `https://pihole.franksdank.cloud/api/...` — authenticate with the session cookie, then query the blocklist, the local DNS records, and the query log
- **Port on the LAN:** `http://192.168.0.143:8083/` (direct, no Caddy)
## Host prerequisites
1. `sysctl net.ipv4.ip_unprivileged_port_start=53` (persisted in `/etc/sysctl.d/99-dnsmasq.conf`) — rootless Podman may then publish port 53.
2. `DNSStubListener=no` in `/etc/systemd/resolved.conf` — the resolved stub would otherwise hold port 53 inside the container netns.
Both prerequisites survive the dnsmasq → Pi-hole swap. Do not remove them.
## Failure modes
| Symptom | First check |
|---------|-------------|
| `dig @192.168.0.143` fails entirely | Quadlet down: `systemctl --user status pihole` |
| A name does not resolve for a new client | The client's `resolv.conf` does not show `192.168.0.143` — the G36 hand-off is missing. See [[LAN-DNS]] |
| The web UI asks for a password loop | `WEBPASSWORD` in the env file is the placeholder `changeme` — fill the real value, restart the unit |
| Upstream queries fail (local names still answer) | `DNS1`/`DNS2` in the env file are missing or wrong |
| Single-label name (for example `dankclaw`) answers `127.0.1.1` | The rootless container `/etc/hosts` carries the host entry (`127.0.1.1 <host>`), and FTL serves it. Use the FQDN, or add an `/etc/hosts` entry on the client |
## See Also
- [[LAN-DNS]] — name resolution flow, router hand-off, split DNS
- [[Caddy]] — the `pihole.franksdank.cloud` vhost
- [[Dankclaw Stack]] — the host that carries Pi-hole