diff --git a/.env.sample b/.env.sample index a02e7c7..5a670e9 100644 --- a/.env.sample +++ b/.env.sample @@ -100,7 +100,7 @@ CADDY_OFFICE_PREFIX=10.0.10 # DNS stack (Technitium) # Bind IP for DNS service (Technitium on Office VLAN 10) -DNS_BIND_IP=10.0.10.3 +DNS_BIND_IP=10.0.10.5 TECHNITIUM_WEB_BIND_IP=0.0.0.0 TECHNITIUM_WEB_PORT=5380 TECHNITIUM_WEB_CONTAINER_PORT=5380 diff --git a/docker-compose-files/caddy/Caddyfile_template b/docker-compose-files/caddy/Caddyfile_template index 235f3cb..0eb3b2c 100644 --- a/docker-compose-files/caddy/Caddyfile_template +++ b/docker-compose-files/caddy/Caddyfile_template @@ -81,7 +81,7 @@ zigbee.{{CADDY_BASE_DOMAIN:-home.example.com}} { ## 2) DNS services dns01.{{CADDY_BASE_DOMAIN:-home.example.com}} { import common - reverse_proxy {{DNS_BIND_IP:-10.0.10.3}}:5380 + reverse_proxy {{DNS_BIND_IP:-10.0.10.5}}:5380 } ## 3) Office services diff --git a/docker-compose-files/caddy/README.md b/docker-compose-files/caddy/README.md index 33f61e4..760805f 100644 --- a/docker-compose-files/caddy/README.md +++ b/docker-compose-files/caddy/README.md @@ -39,7 +39,7 @@ project root. CADDY_LAN_PREFIX=10.0.1 CADDY_OFFICE_PREFIX=10.0.10 CADDY_IOT_PREFIX=10.0.30 - DNS_BIND_IP=10.0.10.3 + DNS_BIND_IP=10.0.10.5 CADDY_MEM_LIMIT=256m DOCKERLOGGING_MAXFILE=3 @@ -99,7 +99,7 @@ docker compose -f docker-compose.caddy.yml exec caddy caddy reload --config /etc In your internal DNS server: -1. Add an `A` record named `caddy` pointing to the Caddy host. +1. Add an `A` record named `caddy` pointing to the Caddy host at `10.0.15.5`. 2. Add a wildcard `CNAME` named `*` pointing to `caddy.home.example.com`. @@ -125,6 +125,31 @@ docker compose -f docker-compose.caddy.yml logs --tail=100 caddy If certificate issuance fails, confirm the Cloudflare token permissions and ensure Caddy's public DNS queries are not redirected to internal DNS. +### Raspberry Pi OS Memory Limits + +If Docker reports the following warning, Caddy still starts, but Docker ignores +`CADDY_MEM_LIMIT`: + +```text +Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded. +``` + +Enable memory cgroups by appending these parameters to the existing single line +in `/boot/firmware/cmdline.txt`: + +```text +cgroup_enable=memory cgroup_memory=1 +``` + +Older Raspberry Pi OS releases may use `/boot/cmdline.txt`. Do not add a new +line to either file. Reboot and verify: + +```bash +sudo reboot +docker info | grep -i warning +docker stats --no-stream caddy +``` + ## Useful Commands ```bash diff --git a/docker-compose-files/technitium/README.md b/docker-compose-files/technitium/README.md index 33f7ed0..265c6fa 100644 --- a/docker-compose-files/technitium/README.md +++ b/docker-compose-files/technitium/README.md @@ -34,7 +34,7 @@ project root. ```dotenv TZ=Africa/Johannesburg - DNS_BIND_IP=10.0.10.3 + DNS_BIND_IP=10.0.10.5 TECHNITIUM_ADMIN_PASSWORD= TECHNITIUM_WEB_BIND_IP=0.0.0.0 @@ -67,7 +67,7 @@ project root. docker compose -f docker-compose.technitium.yml up -d ``` -5. Verify the container and open `http://:5380`: +5. Verify the container and open `http://10.0.10.5:5380`: ```bash docker compose -f docker-compose.technitium.yml ps @@ -91,13 +91,27 @@ In the Technitium admin interface: 1. Create the primary internal zone, for example `home.example.com`. 2. Add records for internal services that do not use Caddy. -3. If using Caddy, add an `A` record named `caddy` pointing to the Caddy host, - then add a wildcard `CNAME` named `*` pointing to - `caddy.home.example.com`. +3. If using Caddy, add an `A` record named `caddy` pointing to `10.0.15.5`, + then add a wildcard `CNAME` named `*` pointing to `caddy.home.example.com`. 4. Configure DHCP to advertise the Technitium host as the DNS server. +5. Configure the recommended blocklists below. Use relative record names such as `caddy` and `*`, not full domain names. +### Recommended Blocklists + +In **Settings > Blocking > Block List URLs**, add the lists you need: + +| Purpose | URL | +|---|---| +| Ads and trackers | `https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/wildcard/pro-onlydomains.txt` | +| Porn / NSFW | `https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/wildcard/nsfw-onlydomains.txt` | +| Gambling | `https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/wildcard/gambling-onlydomains.txt` | + +The wildcard `onlydomains` format uses less memory than hosts-format lists. +Avoid `tif-onlydomains.txt` with the default 512 MB limit because it can cause +`OutOfMemoryException`. Click **Update Now** after changing the lists. + ## Network Requirements - Allow client networks to reach Technitium on TCP and UDP port `53`. @@ -108,18 +122,18 @@ Use relative record names such as `caddy` and `*`, not full domain names. Test DNS from a client: ```bash -nslookup google.com 10.0.10.3 -nslookup proxmox.home.example.com 10.0.10.3 +nslookup google.com 10.0.10.5 +nslookup proxmox.home.example.com 10.0.10.5 ``` -Replace `10.0.10.3` and `home.example.com` with your configured values. +Replace `10.0.10.5` and `home.example.com` with your configured values. ## Troubleshooting The following error means `DNS_BIND_IP` is not assigned to the host: ```text -failed to bind host port 10.0.10.3:53/tcp: cannot assign requested address +failed to bind host port 10.0.10.5:53/tcp: cannot assign requested address ``` Check the host addresses and port usage: @@ -132,6 +146,31 @@ sudo ss -lntup '( sport = :53 )' Set `DNS_BIND_IP` to an assigned address or `0.0.0.0`, render the template again, and restart the stack. +### Raspberry Pi OS Memory Limits + +If Docker reports the following warning, Technitium still starts, but Docker +ignores `TECHNITIUM_MEM_LIMIT`: + +```text +Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded. +``` + +Enable memory cgroups by appending these parameters to the existing single line +in `/boot/firmware/cmdline.txt`: + +```text +cgroup_enable=memory cgroup_memory=1 +``` + +Older Raspberry Pi OS releases may use `/boot/cmdline.txt`. Do not add a new +line to either file. Reboot and verify: + +```bash +sudo reboot +docker info | grep -i warning +docker stats --no-stream technitium-dns +``` + ## Useful Commands ```bash diff --git a/docs/network/udm-pro-zones-migration.md b/docs/network/udm-pro-zones-migration.md index 4723b6d..bd2e992 100644 --- a/docs/network/udm-pro-zones-migration.md +++ b/docs/network/udm-pro-zones-migration.md @@ -12,7 +12,7 @@ Public-safe notation: - Internal domain represented as `home.example.com`. Current deployment: -- Technitium runs in Docker on the Raspberry Pi at `10.0.10.3` on Office VLAN +- Technitium runs in Docker on the Raspberry Pi at `10.0.10.5` on Office VLAN 10. - Office VLAN 10 is assigned to `TRUSTED`, so Technitium is a trusted-zone service. Explicit DNS allow rules are still required from restricted zones. @@ -21,7 +21,7 @@ Current deployment: Complete the migration in this dependency order: -1. **Technitium DNS first:** make `10.0.10.3` authoritative for the internal +1. **Technitium DNS first:** make `10.0.10.5` authoritative for the internal zone and verify direct DNS queries from every current VLAN. 2. **Caddy and DMZ second:** create VLAN 15, move Caddy to `10.0.15.5`, update Technitium's `caddy` record, and verify reverse-proxy and Netbird traffic. @@ -64,7 +64,7 @@ UniFi 9.x permits custom zones. The defaults (`Internal`, `IoT`, `Hotspot`, `DMZ | Zone | Type | VLAN(s) | Members | Consolidates | |---|---|---|---|---| -| **TRUSTED** | Custom | 1 (`10.0.1.0/24`), 10 (`10.0.10.0/24`) | UDM, switch + AP mgmt, workstations, Proxmox host + app VMs, UNAS Pro, and **Technitium DNS (`10.0.10.3`)** | LAN + Office | +| **TRUSTED** | Custom | 1 (`10.0.1.0/24`), 10 (`10.0.10.0/24`) | UDM, switch + AP mgmt, workstations, Proxmox host + app VMs, UNAS Pro, and **Technitium DNS (`10.0.10.5`)** | LAN + Office | | **DMZ** | Custom | 15 (`10.0.15.0/24`) | **Dedicated Caddy host (`10.0.15.5`)** running Netbird agent | New | | **FAMILY** | Custom | 20 (`10.0.20.0/24`) | Family phones / tablets / laptops | Family | | **MEDIA** | Custom | 40 (`10.0.40.0/24`) | PS5, Samsung TV, Apple TV | Media | @@ -87,7 +87,7 @@ firewall policy only when its rollout phase tells you to do so. Step 5 is complete when you have confirmed: - Caddy will use static/reserved address `10.0.15.5`. -- Technitium DNS uses static/reserved address `10.0.10.3`. +- Technitium DNS uses static/reserved address `10.0.10.5`. - The Caddy upstream addresses and ports in §5.4 match the current `docker-compose-files/caddy/Caddyfile_template`. - SLZB-06U uses `10.0.30.5` and the Home Automation host uses `10.0.30.6`. @@ -204,11 +204,11 @@ Create one allow policy for each listed source zone: | Policy name | Action | Source zone | Source IP | Destination zone | Destination IP | Protocol / destination port | |---|---|---|---|---|---|---| -| `ALLOW DMZ to DNS` | Allow | `DMZ` | Any | `TRUSTED` | `10.0.10.3` | TCP and UDP `53` | -| `ALLOW FAMILY to DNS` | Allow | `FAMILY` | Any | `TRUSTED` | `10.0.10.3` | TCP and UDP `53` | -| `ALLOW MEDIA to DNS` | Allow | `MEDIA` | Any | `TRUSTED` | `10.0.10.3` | TCP and UDP `53` | -| `ALLOW IOT to DNS` | Allow | `IOT` | Any | `TRUSTED` | `10.0.10.3` | TCP and UDP `53` | -| `ALLOW GUEST to DNS` | Allow | `GUEST` | Any | `TRUSTED` | `10.0.10.3` | TCP and UDP `53` | +| `ALLOW DMZ to DNS` | Allow | `DMZ` | Any | `TRUSTED` | `10.0.10.5` | TCP and UDP `53` | +| `ALLOW FAMILY to DNS` | Allow | `FAMILY` | Any | `TRUSTED` | `10.0.10.5` | TCP and UDP `53` | +| `ALLOW MEDIA to DNS` | Allow | `MEDIA` | Any | `TRUSTED` | `10.0.10.5` | TCP and UDP `53` | +| `ALLOW IOT to DNS` | Allow | `IOT` | Any | `TRUSTED` | `10.0.10.5` | TCP and UDP `53` | +| `ALLOW GUEST to DNS` | Allow | `GUEST` | Any | `TRUSTED` | `10.0.10.5` | TCP and UDP `53` | ### 5.4 Caddy to TRUSTED backend policies (`BACKEND_APPS`) @@ -228,7 +228,7 @@ Every policy in this table uses: | Policy name | Destination IP | Destination port(s) | Current upstream purpose | |---|---|---|---| | `ALLOW CADDY to LAN web devices` | `10.0.1.5`, `10.0.1.8` | `80` | Lite-8 and TP-Link switch UIs | -| `ALLOW CADDY to Technitium UI` | `10.0.10.3` | `5380` | Technitium admin UI | +| `ALLOW CADDY to Technitium UI` | `10.0.10.5` | `5380` | Technitium admin UI | | `ALLOW CADDY to NAS apps` | `10.0.10.24` | `5000,5055,6767,7878,8000,8080,8096,8191,8282,8989,9696` | NAS and media-stack apps | | `ALLOW CADDY to PBS` | `10.0.10.8` | `8007` | Proxmox Backup Server | | `ALLOW CADDY to Proxmox` | `10.0.10.10` | `8006` | Proxmox | @@ -305,7 +305,7 @@ UniFi default. | 1 | TRUSTED | TRUSTED | Allow | any | Intra-zone (Proxmox ↔ apps ↔ NAS ↔ workstations) | | 2 | TRUSTED | any | Allow | any | Admin path; Trusted is the management zone | -DNS for TRUSTED: DHCP option 6 → `10.0.10.3`. This design does not force DNAT +DNS for TRUSTED: DHCP option 6 → `10.0.10.5`. This design does not force DNAT for TRUSTED because workstations are trusted. Office clients and Technitium share `10.0.10.0/24`, so their DNS traffic does not traverse the UDM Pro SE and cannot be redirected there. LAN VLAN 1 traffic is routed, but remains @@ -383,7 +383,7 @@ Legend: ✅ allow · ❌ block · ⚠ allow only listed flows. Footnotes: 1. **DMZ → TRUSTED pinhole:** Caddy IP only, targeting `BACKEND_APPS` IPs on app-specific TCP ports. Include only routes actually published in `docker-compose-files/caddy/Caddyfile_template`, including Technitium TCP 5380 when `dns01` is enabled. Drop all other DMZ → TRUSTED traffic. -2. **DNS via DNAT redirect** (§8) — destination `10.0.10.3:53` on UDP/TCP only; all other `:53` is silently rewritten. +2. **DNS via DNAT redirect** (§8) — destination `10.0.10.5:53` on UDP/TCP only; all other `:53` is silently rewritten. 3. **Proxy access:** TCP `80, 443` to Caddy IP only. ## 8. DNS Handling — DNAT Redirect Strategy @@ -404,12 +404,12 @@ complexity without matching the policy objective. ### Rules | Zone | DHCP option 6 | DNAT rule | `:53` block | |---|---|---|---| -| TRUSTED | `10.0.10.3` | None | None (trust workstations) | -| DMZ | `10.0.10.3` | — | None (Caddy needs ACME DNS-01 out to WAN) | -| FAMILY | `10.0.10.3` | dst `!10.0.10.3` UDP/TCP 53 → `10.0.10.3:53` | — (DNAT replaces) | -| MEDIA | `10.0.10.3` | same as FAMILY | — | -| IOT | `10.0.10.3` | same as FAMILY | — | -| GUEST | `10.0.10.3` | same as FAMILY | — | +| TRUSTED | `10.0.10.5` | None | None (trust workstations) | +| DMZ | `10.0.10.5` | — | None (Caddy needs ACME DNS-01 out to WAN) | +| FAMILY | `10.0.10.5` | dst `!10.0.10.5` UDP/TCP 53 → `10.0.10.5:53` | — (DNAT replaces) | +| MEDIA | `10.0.10.5` | same as FAMILY | — | +| IOT | `10.0.10.5` | same as FAMILY | — | +| GUEST | `10.0.10.5` | same as FAMILY | — | Practically, this is one DNAT entry with source = group of {FAMILY, MEDIA, IOT, GUEST}. @@ -477,19 +477,19 @@ Media devices (TV, PS5, Apple TV) are wired to TL-SG108 with port-based VLAN 40 ### Phase 1 — Establish Technitium DNS -1. Deploy Technitium at `10.0.10.3` by following the +1. Deploy Technitium at `10.0.10.5` by following the [Technitium deployment guide](../../docker-compose-files/technitium/README.md). 2. Configure the internal primary zone and verify recursion, blocking, and direct lookups from LAN and Office. 3. Add all current and target client networks to Technitium Allowed Networks (§8), including the future DMZ subnet `10.0.15.0/24`. -4. Configure every current VLAN's DHCP option 6 to advertise `10.0.10.3`. +4. Configure every current VLAN's DHCP option 6 to advertise `10.0.10.5`. 5. Add temporary firewall allows for UDP/TCP 53 from every current VLAN to - destination IP `10.0.10.3`. Do not add DNS DNAT yet. + destination IP `10.0.10.5`. Do not add DNS DNAT yet. 6. Renew a client lease on each VLAN and verify both direct and normal resolver queries: ``` - dig @10.0.10.3 example.com + dig @10.0.10.5 example.com dig example.com ``` 7. Continue only after Technitium's query log shows successful requests from @@ -533,7 +533,7 @@ passes without rule misses. ### DNS gate -1. DHCP on every VLAN advertises `10.0.10.3`. +1. DHCP on every VLAN advertises `10.0.10.5`. 2. Direct and normal DNS queries work from every VLAN. 3. Technitium's query log identifies requests from every client subnet. 4. Technitium web administration is reachable only from `TRUSTED`.