feat: wire Pi-hole to forward knel.net to local Technitium + document setup
Add a shared Docker network (dnsnet, 10.53.0.0/24) connecting Pi-hole and
Technitium containers so Pi-hole can conditionally forward knel.net and
Tailscale-reverse queries to the local authoritative Technitium instance
(10.53.0.53) instead of netboot's upstream 192.168.3.16. Also adds
end-to-end documentation for both the reference node (pfv-netboot) and
the replicated nodes (pfv-netinfra-01/02).
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
# pfv-netinfra-01 / pfv-netinfra-02 — Network Services Setup
|
||||
|
||||
These two nodes replicate the network-infrastructure services of **pfv-netboot**
|
||||
(Pi-hole, Technitium DNS, NTP). They were deployed by `setup-netinfra.sh`, which
|
||||
reads config from pfv-netboot (read-only) and relays it to each target.
|
||||
|
||||
## 1. Nodes
|
||||
|
||||
| | pfv-netinfra-01 | pfv-netinfra-02 |
|
||||
|---|---|---|
|
||||
| OS | Debian 13 (trixie), kernel 6.12.96+deb13 | Debian 13 (trixie) |
|
||||
| LAN | `ens18` `192.168.3.252/24` | `ens18` `192.168.3.253/24` |
|
||||
| Tailscale | `100.70.181.72` | `100.93.194.82` |
|
||||
| RAM / Disk | 1.9 GiB / 30 GB (27 GB free) | 3.7 GiB / 30 GB (27 GB free) |
|
||||
| Resolver | Tailscale MagicDNS (`100.100.100.100`) | same |
|
||||
| Docker | 29.6.2 (pre-installed, enabled) | 29.6.2 |
|
||||
| Access | `ssh localuser@pfv-netinfra-0X`, passwordless sudo; `localuser` **not** in docker group → use `sudo docker` | same |
|
||||
|
||||
## 2. Service layout
|
||||
|
||||
All services live under `/home/localuser/services/<svc>/` (owned by `localuser`
|
||||
so the compose files are directly editable; data dirs keep container uids):
|
||||
|
||||
```
|
||||
/home/localuser/services/
|
||||
├── pihole/
|
||||
│ ├── docker-compose.yml
|
||||
│ └── etc-pihole/ # copied from netboot /root/pihole/etc-pihole
|
||||
│ ├── pihole.toml # Pi-hole v6 config (upstreams, etc.)
|
||||
│ ├── gravity.db # adlists / domainlists / clients / groups
|
||||
│ ├── adlists.list
|
||||
│ ├── dnsmasq.conf
|
||||
│ ├── tls.{crt,pem,crt_ca}
|
||||
│ └── versions
|
||||
├── ntp/
|
||||
│ └── docker-compose.yml # chrony container (see §5 — not used; host ntpsec serves)
|
||||
└── technitium/
|
||||
├── docker-compose.yml
|
||||
└── config/ # copied from netboot orphaned volume dns_tsys-dns-config/_data
|
||||
├── dns.config
|
||||
├── auth.config
|
||||
├── scopes/Default.scope
|
||||
├── self-signed-cert.pfx
|
||||
└── zones/ # knel.net.zone + 12 Tailscale reverse zones
|
||||
```
|
||||
|
||||
## 3. Pi-hole (container `pihole`)
|
||||
|
||||
Image `pihole/pihole:latest`; `restart: always`; `cap_add: [SYS_NICE]`.
|
||||
|
||||
| Host port | Container | Purpose |
|
||||
|---|---|---|
|
||||
| `53/tcp`, `53/udp` | 53 | DNS (the LAN/Tailscale recursive resolver) |
|
||||
| `10002/tcp` | 80 | Web admin (HTTP) |
|
||||
| `10003/tcp` | 443 | Web admin (HTTPS) |
|
||||
|
||||
`docker-compose.yml`:
|
||||
```yaml
|
||||
services:
|
||||
pihole:
|
||||
container_name: pihole
|
||||
image: pihole/pihole:latest
|
||||
hostname: pihole
|
||||
ports:
|
||||
- "53:53/tcp"
|
||||
- "53:53/udp"
|
||||
- "10002:80/tcp"
|
||||
- "10003:443/tcp"
|
||||
environment:
|
||||
TZ: 'America/Chicago'
|
||||
FTLCONF_webserver_api_password: 'REDACTED_PASSWORD'
|
||||
FTLCONF_dns_listeningMode: 'all'
|
||||
volumes:
|
||||
- './etc-pihole:/etc/pihole'
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
restart: always
|
||||
```
|
||||
- Upstream DNS (from copied `pihole.toml`): `192.168.3.16`, `8.8.8.8`, `2001:4860:4860::8888`.
|
||||
- Adlist: `https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts`.
|
||||
- `pihole.toml` `interface` was adapted from netboot's `eth0` to the target's `ens18`.
|
||||
- Web admin: `http://<node>:10002/admin/` — password **`REDACTED_PASSWORD`** (same as netboot).
|
||||
- Web UI URL per node: `http://100.70.181.72:10002/admin/` (-01), `http://100.93.194.82:10002/admin/` (-02).
|
||||
|
||||
## 4. Technitium DNS (container `tsys-dns`)
|
||||
|
||||
Image `technitium/dns-server`; `restart: always`. Authoritative DNS for
|
||||
`knel.net` (and Tailscale reverse zones), config copied verbatim from netboot's
|
||||
orphaned `dns_tsys-dns-config` volume.
|
||||
|
||||
| Host port | Container | Purpose |
|
||||
|---|---|---|
|
||||
| `5300/tcp`, `5300/udp` | 53 | DNS (remapped — see note) |
|
||||
| `5380/tcp` | 5380 | Web console (HTTP) |
|
||||
| `53443/tcp` | 53443 | Web console (HTTPS) |
|
||||
|
||||
`docker-compose.yml`:
|
||||
```yaml
|
||||
services:
|
||||
technitium:
|
||||
image: technitium/dns-server
|
||||
container_name: tsys-dns
|
||||
ports:
|
||||
- "5300:53/tcp"
|
||||
- "5300:53/udp"
|
||||
- "5380:5380/tcp"
|
||||
- "53443:53443/tcp"
|
||||
volumes:
|
||||
- './config:/etc/dns'
|
||||
restart: always
|
||||
```
|
||||
- Zones loaded (verified): `knel.net` SOA → `dns.knel.net. hostadmin.knel.net. 2025062313 900 300 604800 900`, plus 12 Tailscale reverse zones.
|
||||
- Web console: `http://<node>:5380/` → user **`admin`** + the original Technitium
|
||||
password (carried over via `auth.config`). If the password is unknown, reset it
|
||||
from the console or by removing `config/auth.config` and recreating the container.
|
||||
- **Port note:** Technitium's native DNS port (53) is remapped to host **5300**
|
||||
because Pi-hole already owns host :53 (they cannot both bind 0.0.0.0:53). To
|
||||
query the authoritative server: `dig -p 5300 @<node> knel.net SOA`. To make
|
||||
Pi-hole resolve `knel.net` via Technitium, add a conditional/local upstream in
|
||||
Pi-hole pointing to the container (e.g. `127.0.0.1#5300` is not host-reachable
|
||||
from Pi-hole's netns — use the docker bridge IP of `tsys-dns`, or add
|
||||
`knel.net` A-records directly in Pi-hole's Local DNS).
|
||||
|
||||
## 5. NTP (host `ntpsec`, not a container)
|
||||
|
||||
Both targets **already run a bare-metal `ntpsec` daemon** (active, enabled) that
|
||||
serves NTP on every local address — including the Tailscale IP — and keeps the
|
||||
system clock synced. This is the **same daemon family as netboot's own bare-metal
|
||||
ntpsec**.
|
||||
|
||||
- **Why no chrony container?** netboot's chrony container (`tsys-ntp`) binds the
|
||||
Tailscale IP `100.103.64.82:123`; on netboot that works only because its ntpsec
|
||||
does **not** pre-bind the specific Tailscale-IP socket. On these targets ntpsec
|
||||
**does** bind the Tailscale IP, so the container cannot claim it (`address
|
||||
already in use`) and would be a non-functional duplicate (verified: the
|
||||
container started but never synced — Stratum 0). It is therefore intentionally
|
||||
**omitted**; host ntpsec provides NTP. `setup-netinfra.sh` detects an active
|
||||
host NTP unit and removes any stale `tsys-ntp` container.
|
||||
- ntpsec config (`/etc/ntpsec/ntp.conf`): Debian NTP pool (`0-3.debian.pool.ntp.org`),
|
||||
`restrict default kod nomodify noquery limited` (serves time, blocks mgmt queries).
|
||||
- Verified sync: -01 stratum 2 (~2 ms offset), -02 stratum 3 (~0.2 ms offset),
|
||||
leap normal.
|
||||
|
||||
The `ntp/docker-compose.yml` is still written on each node for parity/reference
|
||||
(and in case the host NTP is ever disabled — then `sudo docker compose -f
|
||||
/home/localuser/services/ntp/docker-compose.yml up -d` brings up chrony).
|
||||
|
||||
## 6. Verification results (2026-07-28)
|
||||
|
||||
| Check | pfv-netinfra-01 | pfv-netinfra-02 |
|
||||
|---|---|---|
|
||||
| `pihole` health | healthy | healthy |
|
||||
| `dig @127.0.0.1:53 pi.hole` | `172.18.0.2` | `172.18.0.2` |
|
||||
| Pi-hole web `:10002` | HTTP 302 (→login) | HTTP 302 |
|
||||
| `dig @127.0.0.1:5300 knel.net SOA` | SOA answered | SOA answered |
|
||||
| Technitium web `:5380` | HTTP 200 | HTTP 200 |
|
||||
| NTP daemon | ntpsec, stratum 2, synced | ntpsec, stratum 3, synced |
|
||||
|
||||
## 7. Operating the services
|
||||
|
||||
```bash
|
||||
# status
|
||||
sudo docker ps
|
||||
|
||||
# Pi-hole
|
||||
sudo docker compose -f /home/localuser/services/pihole/docker-compose.yml ps
|
||||
sudo docker compose -f /home/localuser/services/pihole/docker-compose.yml logs -f
|
||||
sudo docker exec pihole pihole -v # version
|
||||
sudo docker exec pihole pihole -g # rebuild gravity
|
||||
sudo docker exec pihole pihole -a -p # set/change web password
|
||||
|
||||
# Technitium
|
||||
sudo docker compose -f /home/localuser/services/technitium/docker-compose.yml logs -f
|
||||
sudo docker exec tsys-dns sh # explore /etc/dns
|
||||
|
||||
# NTP (host)
|
||||
systemctl status ntpsec
|
||||
ntpq -pn
|
||||
```
|
||||
|
||||
## 8. Differences from pfv-netboot (intentional)
|
||||
|
||||
1. **Layout** under `/home/localuser/services/` instead of `/root` (so `localuser`
|
||||
can manage compose files); Pi-hole data dir still owned by `localuser`, as on netboot.
|
||||
2. **Pi-hole `interface`** set to `ens18` (targets' NIC) instead of netboot's `eth0`.
|
||||
3. **NTP:** host `ntpsec` (Debian pool) used instead of netboot's chrony container
|
||||
(the container cannot bind the Tailscale IP here; see §5).
|
||||
4. **Technitium DNS** host port remapped `53 → 5300` to avoid clashing with Pi-hole
|
||||
on `:53`. The `knel.net` zone and all reverse zones are identical to netboot's.
|
||||
5. Pi-hole query logs (`pihole-FTL.db*`) and regenerable caches/backups are not
|
||||
copied (transient); gravity DB and all configuration are.
|
||||
|
||||
## 9. Re-running / reproducing
|
||||
|
||||
`setup-netinfra.sh` is **idempotent** — it skips re-copying config if already
|
||||
present and uses `docker compose up -d` (no-ops when unchanged). It reads
|
||||
pfv-netboot read-only and never mutates it.
|
||||
|
||||
```bash
|
||||
./setup-netinfra.sh # deploy to both nodes
|
||||
./setup-netinfra.sh pfv-netinfra-01 # deploy one node
|
||||
./setup-netinfra.sh pfv-netinfra-01 verify # verify only
|
||||
```
|
||||
|
||||
Prerequisites: SSH key access to all three hosts as `localuser` with passwordless
|
||||
sudo; the targets reach `192.168.3.16`/`8.8.8.8` for Pi-hole upstream and the
|
||||
internet for image pulls.
|
||||
|
||||
## 10. Files in this directory
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `setup-netinfra.sh` | orchestrator: deploys + verifies the clone on -01/-02 |
|
||||
| `audit-netboot.sh` | broad read-only audit of pfv-netboot |
|
||||
| `deep-audit-netboot.sh` | docker inspect / compose / volume deep audit (read-only) |
|
||||
| `gather-configs.sh` | targeted config pull (pihole.toml, technitium) (read-only) |
|
||||
| `baseline.sh` | read-only baseline of a target node |
|
||||
| `netboot-audit.txt`, `netboot-deep-audit.txt`, `netboot-configs.txt` | audit output |
|
||||
| `pfv-netboot-setup.md` | reference-node documentation |
|
||||
| `pfv-netinfra-setup.md` | this document |
|
||||
Reference in New Issue
Block a user