# Technitium DNS Docker deployment for Technitium DNS Server. Run all commands from the repository root. ## Persistent Data Technitium configuration, zones, and application state are stored in the Docker-managed named volume `technitium_data`. Existing deployments that use `appdata/technitium` must copy that data into the named volume before recreating the container. ## Installation 1. Create `.env` if it does not exist: ```bash cp -n .env.sample .env ``` 2. Check the host addresses, then set the required values in `.env`: ```bash ip -br address ``` ```dotenv TZ=Africa/Johannesburg DNS_BIND_IP=10.0.10.5 TECHNITIUM_ADMIN_PASSWORD= TECHNITIUM_WEB_BIND_IP=0.0.0.0 TECHNITIUM_WEB_PORT=5380 TECHNITIUM_MEM_LIMIT=512m DOCKERLOGGING_MAXFILE=3 DOCKERLOGGING_MAXSIZE=10m ``` `DNS_BIND_IP` must be assigned to the host. Use `0.0.0.0` to listen on every host interface. 3. Render the template: ```bash ./substitute_env.sh docker-compose-files/technitium/template.yaml docker-compose.technitium.yml .env ``` `docker-compose.technitium.yml` contains the rendered admin password and is ignored by Git. 4. Validate and start Technitium: ```bash docker compose -f docker-compose.technitium.yml config --quiet docker compose -f docker-compose.technitium.yml up -d ``` 5. Verify the container and open `http://10.0.10.5:5380`: ```bash docker compose -f docker-compose.technitium.yml ps docker compose -f docker-compose.technitium.yml logs --tail=100 technitium-dns ``` ## Apply Configuration Changes After changing `.env` or `template.yaml`, render the Compose file and recreate the container: ```bash ./substitute_env.sh docker-compose-files/technitium/template.yaml docker-compose.technitium.yml .env docker compose -f docker-compose.technitium.yml config --quiet docker compose -f docker-compose.technitium.yml up -d ``` ## Initial Setup 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 `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. ## Enable On UDM Pro SE Use this sequence with the latest UniFi OS and UniFi Network. It follows the current zone design (see [firewall-rules.md](../../docs/network/firewall-rules.md)): - Technitium: `10.0.10.5`, Office VLAN 10, `TRUSTED` zone - Caddy: `10.0.15.5`, DMZ VLAN 15, `DMZ` zone - Current client VLANs: LAN, Office, Family, IoT, Media, and Guest Complete **Use Technitium Now** first. The custom-zone and DNS-enforcement steps are later migration work; do not configure them until normal DNS works from every VLAN. ### Use Technitium Now #### 1. Confirm Technitium Answers DNS From an Office VLAN client: ```bash nslookup google.com 10.0.10.5 ``` Expected result: the command returns one or more addresses and identifies `10.0.10.5` as the DNS server. #### 2. Confirm Technitium Allows Your VLANs The Compose template initializes Technitium with recursion enabled for private networks. To verify or change this in the latest Technitium web console: 1. Open `http://10.0.10.5:5380`. 2. Open **Settings** from the main navigation. 3. Find the **Recursion** section on the Settings page. 4. Set **Recursion** to **Use Specified Network ACL**. 5. In **Recursion Network ACL**, allow these networks in this order: ```text 127.0.0.1/32 ::1/128 10.0.1.0/24 10.0.10.0/24 10.0.15.0/24 10.0.20.0/24 10.0.30.0/24 10.0.40.0/24 10.0.50.0/24 ``` 6. Save the Settings page. `Recursion Network ACL` is the current field name. There is no separate **Settings > DNS Server** menu. Technitium reads the Docker recursion environment variables only when creating its configuration for the first time. For an existing installation, the saved value shown on the Settings page is authoritative. #### 3. Test Direct DNS From Every VLAN Connect a client to each current VLAN and run: ```bash nslookup google.com 10.0.10.5 ``` Expected result: every VLAN receives a DNS answer from `10.0.10.5`. If a VLAN times out, create a temporary firewall allow before continuing: 1. In UniFi Network, open **Settings > Policy Engine > Policy Table**. 2. Create a new **Firewall** policy with action **Allow**. 3. Select the VLAN's current source zone and the specific source network. 4. Set destination zone to `TRUSTED`. 5. Set destination matcher to **IP** and enter `10.0.10.5`. 6. Select IPv4, protocol **TCP/UDP**, and destination port `53`. 7. Save the policy and retest the direct query. Do not create final FAMILY, MEDIA, IOT, GUEST, or DMZ zone policies until those custom zones exist. #### 4. Advertise Technitium Through UDM DHCP Repeat these steps for LAN, Office, Family, IoT, Media, and Guest: 1. In UniFi Network, open **Settings > Networks**. 2. Select the network. 3. Find the DHCP settings. In the current UI this is normally under **DHCP Service Management**. 4. Set the DHCP DNS server/name server to **Manual**. 5. Enter only `10.0.10.5`. Do not add a public secondary resolver. 6. Save the network. 7. Reconnect the client or renew its DHCP lease. This is a per-network DHCP setting. Do not change the UDM's WAN/Internet DNS setting. #### 5. Verify Clients Use Technitium From one renewed client on each VLAN: ```bash nslookup google.com ``` Expected result: the output identifies `10.0.10.5` as the server and returns a DNS answer. The Technitium Dashboard query counters and client statistics should increase. Stop here until normal DNS works from every VLAN. ### Later: Apply Final Zone Policies Create these only while migrating each VLAN into its target custom zone: | Name | Source zone | Destination zone | Destination IP | Protocol | Destination port | |---|---|---|---|---|---| | `ALLOW DMZ to DNS` | `DMZ` | `TRUSTED` | `10.0.10.5` | TCP/UDP | `53` | | `ALLOW FAMILY to DNS` | `FAMILY` | `TRUSTED` | `10.0.10.5` | TCP/UDP | `53` | | `ALLOW MEDIA to DNS` | `MEDIA` | `TRUSTED` | `10.0.10.5` | TCP/UDP | `53` | | `ALLOW IOT to DNS` | `IOT` | `TRUSTED` | `10.0.10.5` | TCP/UDP | `53` | | `ALLOW GUEST to DNS` | `GUEST` | `TRUSTED` | `10.0.10.5` | TCP/UDP | `53` | Place each DNS allow above that zone's RFC1918 and terminal block policies. Remove the matching temporary rule after the final rule works. ### Later: Enable DNS Enforcement UniFi Network 10.4.57 does not expose supported LAN-facing DNS DNAT. After the final zone policies and DHCP-provided DNS work, verify that each restricted zone can query Technitium and that port 53 queries to other destinations are blocked. Do not block public DNS from `TRUSTED` or `DMZ`. Office clients are trusted, and Caddy in DMZ must query public resolvers for ACME DNS-01. ## Network Requirements - Allow client networks to reach Technitium on TCP and UDP port `53`. - Restrict the web admin port `5380` to trusted administration networks. - If `DNS_BIND_IP=0.0.0.0`, use firewall rules to restrict DNS access. - Ensure no other service on the host is already using port `53`. Test DNS from a client: ```bash nslookup google.com 10.0.10.5 nslookup proxmox.home.example.com 10.0.10.5 ``` 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.5:53/tcp: cannot assign requested address ``` Check the host addresses and port usage: ```bash ip -br address 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 # Published admin port docker compose -f docker-compose.technitium.yml port technitium-dns 5380 ``` ## Backup Back up the `technitium_data` named volume. It contains the DNS configuration, zones, and application state.