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
9.2 KiB
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:
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: 'Gransyan1!'
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.tomlinterfacewas adapted from netboot'seth0to the target'sens18.- Web admin:
http://<node>:10002/admin/— passwordGransyan1!(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:
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.netSOA →dns.knel.net. hostadmin.knel.net. 2025062313 900 300 604800 900, plus 12 Tailscale reverse zones. - Web console:
http://<node>:5380/→ useradmin+ the original Technitium password (carried over viaauth.config). If the password is unknown, reset it from the console or by removingconfig/auth.configand 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 resolveknel.netvia Technitium, add a conditional/local upstream in Pi-hole pointing to the container (e.g.127.0.0.1#5300is not host-reachable from Pi-hole's netns — use the docker bridge IP oftsys-dns, or addknel.netA-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 IP100.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.shdetects an active host NTP unit and removes any staletsys-ntpcontainer. - 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
# 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)
- Layout under
/home/localuser/services/instead of/root(solocalusercan manage compose files); Pi-hole data dir still owned bylocaluser, as on netboot. - Pi-hole
interfaceset toens18(targets' NIC) instead of netboot'seth0. - NTP: host
ntpsec(Debian pool) used instead of netboot's chrony container (the container cannot bind the Tailscale IP here; see §5). - Technitium DNS host port remapped
53 → 5300to avoid clashing with Pi-hole on:53. Theknel.netzone and all reverse zones are identical to netboot's. - 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.
./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 |