homelab-blueprint/docker-compose-files/technitium/README.md
Brian Pooe 1815beadf4 refactor: restructure docs, sync stacks with Caddyfile, harden compose templates
- Add compose stacks for apps already proxied by Caddy: bento-pdf,
  it-tools, paperless-ngx, and beszel-hub (with Makefile targets)
- Remove the unused Vault stack and the drawio Caddyfile block
- Fix Caddyfile gramps upstream to port 80 to match the compose file
- Bring immich and gramps-web up to the shared template pattern
  (no-new-privileges, log rotation, memory limits, healthchecks)
- Single-quote vaultwarden SSO_AUDIENCE_TRUSTED so regex values like
  ^\d{18}$ render as valid YAML
- Move root docs into kebab-case topic folders, rebuild the docs index
  to cover every doc, and fix all broken links
2026-07-03 17:45:16 +02:00

9.3 KiB

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:

    cp -n .env.sample .env
    
  2. Check the host addresses, then set the required values in .env:

    ip -br address
    
    TZ=Africa/Johannesburg
    DNS_BIND_IP=10.0.10.5
    TECHNITIUM_ADMIN_PASSWORD=<strong-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:

    ./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:

    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:

    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:

./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.

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):

  • 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:

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:
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
  1. 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:

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:

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:

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:

failed to bind host port 10.0.10.5:53/tcp: cannot assign requested address

Check the host addresses and port usage:

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:

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:

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:

sudo reboot
docker info | grep -i warning
docker stats --no-stream technitium-dns

Useful Commands

# 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.