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,116 @@
|
||||
# pfv-netboot — Reference Network Infrastructure (READ-ONLY reference)
|
||||
|
||||
> **Status:** REFERENCE SOURCE ONLY. This node is production infrastructure.
|
||||
> Do **not** modify it. This document describes it as audited so its services can
|
||||
> be replicated to `pfv-netinfra-01` / `pfv-netinfra-02`. All data below was
|
||||
> collected by **read-only** audit scripts (`audit-netboot.sh`,
|
||||
> `deep-audit-netboot.sh`, `gather-configs.sh`) on 2026-07-27/28.
|
||||
|
||||
## 1. Host
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| Hostname / FQDN | `pfv-netboot` / `pfv-netboot.knel.net` |
|
||||
| OS | Debian GNU/Linux 12 (bookworm), kernel 6.1.0-44-amd64 |
|
||||
| Hardware | 2 vCPU, ~1.9 GiB RAM, 491 GB disk (18 GB used) |
|
||||
| Timezone | `America/Chicago` (US/Central) |
|
||||
| LAN | `eth0` static `192.168.3.250/22`, gw `192.168.3.254` (`/etc/network/interfaces`) |
|
||||
| Tailscale | `100.103.64.82` (`tailscale0`) |
|
||||
| DNS resolver | Tailscale MagicDNS — `/etc/resolv.conf` → `100.100.100.100` |
|
||||
| Docker | Docker Engine 29.6.2 (containerd v2.2.6, runc 1.3.6) |
|
||||
| Access | `localuser` has passwordless sudo; **not** in `docker` group (uses `sudo docker`) |
|
||||
|
||||
`eth1` is up but unconfigured; many docker bridges exist (`pihole_default`,
|
||||
`ntp_default`, `dns_default`, and several stale ones).
|
||||
|
||||
## 2. Services overview
|
||||
|
||||
| Service | Form | Running? |
|
||||
|---|---|---|
|
||||
| **Pi-hole** (DNS sinkhole, recursive resolver) | Docker container `pihole` | ✅ healthy |
|
||||
| **NTP** — overlay on Tailscale IP | Docker container `tsys-ntp` (`dockurr/chrony`) | ✅ healthy |
|
||||
| **NTP** — system clock + LAN serving | bare-metal `ntpsec` (`ntpd`) | ✅ active, enabled |
|
||||
| **Technitium DNS** (authoritative for `knel.net`) | Docker container | ❌ **not running**; config preserved in orphaned volume |
|
||||
|
||||
## 3. Pi-hole (container)
|
||||
|
||||
- **Compose:** `/root/pihole/docker-compose.yml` (compose project `pihole`)
|
||||
- **Image:** `pihole/pihole:latest` — Core **v6.1.2**, Web v6.2.1, FTL v6.2.2
|
||||
- **Container:** `pihole`, `restart: always`, `cap_add: [SYS_NICE]`, network `pihole_default`
|
||||
- **Ports (host):**
|
||||
|
||||
| Host | Container | Purpose |
|
||||
|---|---|---|
|
||||
| `53/tcp`, `53/udp` | 53 | DNS |
|
||||
| `10002/tcp` | 80 | Web admin (HTTP) |
|
||||
| `10003/tcp` | 443 | Web admin (HTTPS, self-signed) |
|
||||
|
||||
- **Environment:** `TZ=America/Chicago`, `FTLCONF_webserver_api_password=Gransyan1!`, `FTLCONF_dns_listeningMode=all`
|
||||
- **Data:** bind mount `/root/pihole/etc-pihole:/etc/pihole` (dir owned by `localuser`; files by container `pihole` uid)
|
||||
- **Config (Pi-hole v6 TOML):** `pihole.toml`. Key settings:
|
||||
- Upstream DNS: `192.168.3.16`, `8.8.8.8`, `2001:4860:4860::8888`
|
||||
- `listeningMode = "ALL"`, `interface = "eth0"`, `dns.port = 53`, `dns.domain = "lan"`
|
||||
- `queryLogging = true`, DNSSEC off
|
||||
- **Adlists:** one entry — `https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts` (in `gravity.db`/`adlists.list`)
|
||||
- **Gravity DB:** `/etc/pihole/gravity.db` (~5.5 MB) holds adlists/domainlists/clients/groups
|
||||
- **Web admin:** `http://pfv-netboot:10002/admin/` (password `Gransyan1!`)
|
||||
- Note: query history `pihole-FTL.db` (~2.5 GB) is transient and **excluded** from replication.
|
||||
|
||||
## 4. NTP (two layers)
|
||||
|
||||
### 4a. chrony container (`tsys-ntp`) — overlay on the Tailscale IP
|
||||
- **Compose:** `/root/NTP/docker-compose.yml` (project `ntp`)
|
||||
- **Image:** `dockurr/chrony`
|
||||
- **Env:** `NTP_SERVERS=pool.ntp.org`
|
||||
- **Ports:** `100.103.64.82:123:123/udp` — bound specifically to the **Tailscale IP**
|
||||
- `restart: always`
|
||||
- chrony.conf (generated): `server pool.ntp.org iburst`, `allow all`, `rtcsync`
|
||||
- On netboot this coexists with bare-metal ntpsec because ntpsec here does **not** pre-bind the specific Tailscale-IP socket, letting Docker claim it.
|
||||
|
||||
### 4b. bare-metal `ntpsec`
|
||||
- Unit `ntpsec.service` — active, enabled; `/usr/sbin/ntpd -c /etc/ntpsec/ntp.conf -g -N -u ntpsec:ntpsec`
|
||||
- **Config** (`/etc/ntpsec/ntp.conf`):
|
||||
```
|
||||
driftfile /var/lib/ntp/ntp.drift
|
||||
leapfile /usr/share/zoneinfo/leap-seconds.list
|
||||
server pfvsvrpi.knel.net
|
||||
restrict 127.0.0.1
|
||||
restrict ::1
|
||||
```
|
||||
- Listens on all local addresses (incl. Tailscale) for UDP/123; serves LAN clients.
|
||||
|
||||
## 5. Technitium DNS (currently stopped)
|
||||
|
||||
- **Not running** — no container and **no compose file** exists for it.
|
||||
- A previous deployment left an **orphaned Docker volume** `dns_tsys-dns-config`
|
||||
(mountpoint `/var/lib/docker/volumes/dns_tsys-dns-config/_data`) whose contents
|
||||
are intact (last activity 2025-06-23). A second typo'd volume
|
||||
`dns_tyss-dns-config` is empty.
|
||||
- Config files are **binary** (Technitium's own serialization), but copy verbatim:
|
||||
`dns.config`, `auth.config`, `log.config`, `scopes/Default.scope`,
|
||||
`self-signed-cert.pfx`, `cache.bin`, `zones/`, `stats/`, `logs/`.
|
||||
- **Zones present** (12 reverse + 1 forward):
|
||||
- `knel.net.zone` — forward zone; SOA `dns.knel.net. hostadmin.knel.net.` (serial `2025062313`). A-records for the internal fleet, including: `tsys1`, `rr-middleware`, `pfv-netboot`, `pfv-k8s-cnode1`…`cnode5`, `pfv-k8s-wnode3`, `tsys-k8scloud-netcup-1`, `tsys-kali-vptechops`, `tsys-kali-dev`; NS `dns.knel.net`.
|
||||
- Reverse zones for Tailscale CGNAT ranges (`100.x.in-addr.arpa`): `199.86`, `145.105`, `181.103`, `184.108`, `194.67`, `2.108`, `211.114`, `46.96`, `64.103`, `75.110`, `97.82`, `119.127`.
|
||||
- **Auth:** `auth.config` defines user `admin` (Administrators group) with a stored password hash; the plaintext password is whatever was set on the original Technitium instance.
|
||||
- The compose project name historically was `dns` (network `dns_default` still exists).
|
||||
|
||||
## 6. Firewall / misc
|
||||
|
||||
- nftables/iptables: mostly Docker + Tailscale chains (`ts-input`, `ts-forward`,
|
||||
`DOCKER`, `DOCKER-FORWARD`); default `INPUT ACCEPT`, `FORWARD DROP`,
|
||||
`OUTPUT ACCEPT`. No UFW / firewalld.
|
||||
- Also runs (out of scope for this replication): Samba (137/138/139, 445), NFS
|
||||
(2049), rpcbind (111), Postfix (25), Cockpit (9090), Beszel agent, webmin/
|
||||
usermin (10000/10002/20000), Tailscale (41641).
|
||||
- SELinux absent; AppArmor default docker profile.
|
||||
|
||||
## 7. How it was audited (no changes made)
|
||||
|
||||
```bash
|
||||
ssh localuser@pfv-netboot 'bash -s' < audit-netboot.sh # broad read-only sweep
|
||||
ssh localuser@pfv-netboot 'bash -s' < deep-audit-netboot.sh # docker inspect + compose
|
||||
ssh localuser@pfv-netboot 'bash -s' < gather-configs.sh # pihole.toml + technitium
|
||||
```
|
||||
|
||||
Artifacts: `netboot-audit.txt`, `netboot-deep-audit.txt`, `netboot-configs.txt`.
|
||||
@@ -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: '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.toml` `interface` was adapted from netboot's `eth0` to the target's `ens18`.
|
||||
- Web admin: `http://<node>:10002/admin/` — password **`Gransyan1!`** (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 |
|
||||
+57
-17
@@ -60,6 +60,10 @@ sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' 2>&1
|
||||
echo
|
||||
echo "### Pi-hole DNS (dig @127.0.0.1:53 pi.hole) ###"
|
||||
dig +time=3 +tries=1 +short @127.0.0.1 -p 53 pi.hole 2>&1
|
||||
echo "### Pi-hole -> Technitium (dig @53 knel.net SOA) ###"
|
||||
dig +time=3 +tries=1 +short @127.0.0.1 -p 53 knel.net SOA 2>&1
|
||||
echo "### Pi-hole -> Technitium (dig @53 pfv-netboot.knel.net A) ###"
|
||||
dig +time=3 +tries=1 +short @127.0.0.1 -p 53 pfv-netboot.knel.net A 2>&1
|
||||
echo "### Pi-hole web (curl :10002) ###"
|
||||
curl -sk -o /dev/null -w 'http=%{http_code}\n' http://127.0.0.1:10002/admin/ 2>&1
|
||||
echo
|
||||
@@ -68,10 +72,18 @@ dig +time=3 +tries=1 @127.0.0.1 -p 5300 knel.net SOA +short 2>&1
|
||||
echo "### Technitium web (curl :5380) ###"
|
||||
curl -sk -o /dev/null -w 'http=%{http_code}\n' http://127.0.0.1:5380/ 2>&1
|
||||
echo
|
||||
echo "### NTP on tailscale IP (ntpdig -p 1) ###"
|
||||
timeout 5 ntpdig -t1 -c1 -p1 $tsip 2>&1 || echo "(ntpdig not available or no response)"
|
||||
echo "### chrony container sources ###"
|
||||
sudo docker exec tsys-ntp chronyc -n sources 2>&1 | head -8
|
||||
echo "### NTP service ###"
|
||||
HOST_NTP=""
|
||||
for u in ntpsec ntp chrony openntpd; do
|
||||
systemctl is-active --quiet "\$u" 2>/dev/null && { HOST_NTP="\$u"; break; }
|
||||
done
|
||||
echo "host daemon: \${HOST_NTP:-none}"
|
||||
if [ -n "\$HOST_NTP" ]; then
|
||||
ntpq -c "rv 0 leap,stratum,offset" 2>&1 | head -3
|
||||
else
|
||||
echo "(no host NTP; chrony container:)"
|
||||
sudo docker exec tsys-ntp chronyc -n tracking 2>&1 | head -6
|
||||
fi
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -112,6 +124,12 @@ services:
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
restart: always
|
||||
networks:
|
||||
- default
|
||||
- dnsnet
|
||||
networks:
|
||||
dnsnet:
|
||||
external: true
|
||||
YAML
|
||||
|
||||
on_node "$node" "cat > $SVC_ROOT/ntp/docker-compose.yml" <<YAML
|
||||
@@ -139,6 +157,13 @@ services:
|
||||
volumes:
|
||||
- './config:/etc/dns'
|
||||
restart: always
|
||||
networks:
|
||||
default:
|
||||
dnsnet:
|
||||
ipv4_address: 10.53.0.53
|
||||
networks:
|
||||
dnsnet:
|
||||
external: true
|
||||
YAML
|
||||
|
||||
# ---- 3. Relay Pi-hole config from netboot -> target ---------------------
|
||||
@@ -167,8 +192,8 @@ YAML
|
||||
| on_node "$node" "sudo tar -xf - -C $SVC_ROOT/technitium && sudo mv $SVC_ROOT/technitium/_data $SVC_ROOT/technitium/config"
|
||||
fi
|
||||
|
||||
# ---- 5. Adapt copied config: Pi-hole interface name ---------------------
|
||||
log "$node: adapt Pi-hole pihole.toml interface name to actual iface"
|
||||
# ---- 5. Adapt copied config: interface + repoint knel.net to local Technitium
|
||||
log "$node: adapt Pi-hole pihole.toml (interface + revServer -> local Technitium)"
|
||||
on_node "$node" "bash -s" <<'EOF'
|
||||
set -e
|
||||
IFACE=$(ip -o -4 route show to default 2>/dev/null | awk '{print $5; exit}')
|
||||
@@ -177,12 +202,24 @@ TOML=/home/localuser/services/pihole/etc-pihole/pihole.toml
|
||||
if sudo test -f "$TOML"; then
|
||||
sudo sed -i "s|^ interface = .*| interface = \"$IFACE\" ### ADAPTED from eth0 on clone|" "$TOML"
|
||||
echo "set interface=$IFACE"
|
||||
# Repoint knel.net conditional forward from netboot's upstream (192.168.3.16)
|
||||
# to the LOCAL Technitium container at its fixed dnsnet IP 10.53.0.53.
|
||||
# Subnet 100.64.0.0/10 = Tailscale CGNAT range (covers all Tailscale reverse zones).
|
||||
if sudo grep -q 'revServers' "$TOML"; then
|
||||
sudo sed -i 's|"true,[0-9./]*,192\.168\.3\.16,knel\.net"|"true,100.64.0.0/10,10.53.0.53,knel.net"|' "$TOML"
|
||||
echo "revServer repointed to 10.53.0.53 (local Technitium)"
|
||||
else
|
||||
echo "(revServers not found; FTL will use defaults)"
|
||||
fi
|
||||
else
|
||||
echo "(pihole.toml not present; FTL will create it on first run)"
|
||||
fi
|
||||
# Strip netboot-specific primary upstream 192.168.3.16? -> keep, it is reachable on LAN.
|
||||
EOF
|
||||
|
||||
# ---- 5b. Create shared Docker network for Pi-hole <-> Technitium ----------
|
||||
log "$node: create dnsnet shared Docker network (10.53.0.0/24)"
|
||||
on_node "$node" "sudo docker network create --subnet 10.53.0.0/24 dnsnet 2>/dev/null || true"
|
||||
|
||||
# ---- 6. Pull images -----------------------------------------------------
|
||||
log "$node: docker compose pull (pihole, ntp, technitium)"
|
||||
on_node "$node" "bash -s" <<EOF
|
||||
@@ -203,20 +240,23 @@ EOF
|
||||
# there does not pre-bind the specific tailscale-IP socket. On these targets
|
||||
# ntpsec DOES bind the tailscale IP, so the container cannot claim it and is
|
||||
# redundant anyway. We therefore keep the host ntpsec as the NTP service.
|
||||
log "$node: NTP -- check whether host already serves UDP/123"
|
||||
log "$node: NTP -- detect host NTP service"
|
||||
on_node "$node" "bash -s" <<'EOF'
|
||||
set +e
|
||||
HOST_NTP=$(sudo ss -lun 2>/dev/null | awk '$5 ~ /:123$/ {print}' | head -1)
|
||||
HOST_NTP=""
|
||||
for u in ntpsec ntp chrony openntpd; do
|
||||
if systemctl is-active --quiet "$u" 2>/dev/null; then HOST_NTP="$u"; break; fi
|
||||
done
|
||||
if [ -n "$HOST_NTP" ]; then
|
||||
echo "Host already serves UDP/123 ($HOST_NTP); host daemon:"
|
||||
for u in ntpsec ntp chrony openntpd systemd-timesyncd; do
|
||||
systemctl is-active "$u" 2>/dev/null | grep -q active && echo " -> $u active"
|
||||
done
|
||||
echo "Skipping chrony container (host NTP provides the service)."
|
||||
echo "Removing any stale tsys-ntp container..."
|
||||
sudo docker rm -f tsys-ntp 2>/dev/null || true
|
||||
echo "Host NTP daemon '$HOST_NTP' is active -- it serves NTP on all local"
|
||||
echo "addresses (incl. the Tailscale IP). This is the same daemon family as"
|
||||
echo "netboot's bare-metal ntpsec; the netboot chrony container is redundant"
|
||||
echo "here and CANNOT bind the Tailscale IP (the host daemon already owns it)."
|
||||
echo "-> Keeping host NTP. Removing any stale chrony container (tsys-ntp)."
|
||||
sudo docker rm -f tsys-ntp 2>/dev/null && echo " (removed tsys-ntp)" || echo " (no tsys-ntp to remove)"
|
||||
echo " host peers:"; ntpq -pn 2>/dev/null | head -12 || true
|
||||
else
|
||||
echo "Nothing serving UDP/123; starting chrony container."
|
||||
echo "No host NTP daemon active; starting chrony container."
|
||||
sudo docker compose -f /home/localuser/services/ntp/docker-compose.yml up -d
|
||||
fi
|
||||
EOF
|
||||
|
||||
Reference in New Issue
Block a user