In modern home and office environments, robust domain-level filtering is no longer a luxury—it is a security requirement. Services like NextDNS offer excellent cloud-managed filtering to block ads, trackers, malware, gambling, and addictive gaming platforms like Roblox.
However, NextDNS's free tier imposes a strict limit of 300,000 queries per month. For a household or small office with multiple active devices, smart TVs, and background telemetry, this limit can easily be exhausted within a week. Once exceeded, your custom filtering rules stop working, leaving your network unprotected.
The solution? A hybrid self-hosted DNS architecture. By deploying Technitium DNS Server on your own server, you can cache queries locally, reducing the outbound query volume forwarded to NextDNS by up to 80% to 90%. This guide walks through the step-by-step installation and configuration of this setup using Docker Compose and Traefik.
The Hybrid Architecture
By combining a local Technitium instance with NextDNS as an upstream forwarder, you get the best of both worlds:
- Local Caching: The vast majority of DNS queries are recurrent (e.g., polling API endpoints, social media domains). Technitium caches these responses locally, serving them with sub-millisecond latency.
- Reduced NextDNS Queries: Because cached queries are resolved locally, only unique, uncached queries are forwarded to NextDNS. This easily keeps your NextDNS query volume well below the 300k free-tier threshold.
- Double-Layer Filtering: You can run Technitium's native blocklists (for ads, porn, gambling) directly on the server, while utilizing NextDNS's advanced cloud categories for secondary protection.
- Secure Transport: Outbound queries to NextDNS are fully encrypted using DNS-over-QUIC (DoQ) to prevent ISP interception.
graph TD
Client[Client Device] -->|DNS Query| Tech[Technitium DNS Server]
Tech -->|1. Cache Hit| Client
Tech -->|2. Cache Miss / Encrypted DoQ| NextDNS[NextDNS Upstream Resolver]
NextDNS -->|3. Resolve & Filter| Tech
Docker Compose Configuration
To deploy the DNS server, we will containerize Technitium and route its web dashboard and encrypted DNS interfaces through the Traefik reverse proxy.
You can edit the variables <YOUR_DOMAIN>, <NEXTDNS_ENDPOINT>, and <ADMIN_PASSWORD> directly in the code block below to customize your configuration!
services:
dns-server:
container_name: dns-server
hostname: dns-server
image: docker.io/technitium/dns-server:15.2.0
ports:
- "53:53/udp" # Standard DNS over UDP
- "53:53/tcp" # Standard DNS over TCP
environment:
- DNS_SERVER_DOMAIN=<YOUR_DOMAIN>
- DNS_SERVER_ADMIN_PASSWORD=<ADMIN_PASSWORD> # 👈 Set your admin password here
- DNS_SERVER_PREFER_IPV6=false
- DNS_SERVER_LOG_FOLDER_PATH=/var/log/technitium/dns
- DNS_SERVER_LOG_USING_LOCAL_TIME=true
- DNS_SERVER_LOG_MAX_LOG_FILE_DAYS=365
- DNS_SERVER_STATS_ENABLE_IN_MEMORY_STATS=false
- DNS_SERVER_STATS_MAX_STAT_FILE_DAYS=365
# --- DNS Filtering & Forwarding Toggles ---
- DNS_SERVER_ENABLE_BLOCKING=true
- DNS_SERVER_ALLOW_TXT_BLOCKING_REPORT=true
- DNS_SERVER_FORWARDERS=<NEXTDNS_ENDPOINT>:853 # 👈 Replace with your NextDNS endpoint
- DNS_SERVER_FORWARDER_PROTOCOL=Quic # 👈 High-performance DNS-over-QUIC
- DNS_SERVER_RECURSION=Allow
# --- Reverse Proxy / DoH Settings ---
- DNS_SERVER_OPTIONAL_PROTOCOL_DNS_OVER_HTTP=true
- DNS_SERVER_WEB_SERVICE_HTTP_PORT=5380
volumes:
- ./config:/etc/dns
- ./logs:/var/log/technitium/dns
restart: unless-stopped
sysctls:
- net.ipv4.ip_local_port_range=1024 65535
networks:
- frontend
- backend
labels:
- "traefik.enable=true"
- "traefik.docker.network=frontend"
# --- HTTP to HTTPS Redirect ---
- "traefik.http.middlewares.dns-https-redirect.redirectscheme.scheme=https"
# --- HTTP Router (Web Admin Console) ---
- "traefik.http.routers.dns-http.rule=Host("<YOUR_DOMAIN>")"
- "traefik.http.routers.dns-http.entrypoints=web"
- "traefik.http.routers.dns-http.middlewares=dns-https-redirect"
# --- HTTPS Router 1: Web Admin Console (Port 5380) ---
- "traefik.http.routers.dns-secure.rule=Host("<YOUR_DOMAIN>")"
- "traefik.http.routers.dns-secure.entrypoints=websecure"
- "traefik.http.routers.dns-secure.service=dns-dashboard-svc"
- "traefik.http.routers.dns-secure.tls=true"
- "traefik.http.routers.dns-secure.tls.certresolver=cloudflare"
# --- HTTPS Router 2: DNS-over-HTTPS Endpoint (Port 8053) ---
- "traefik.http.routers.dns-doh-secure.rule=Host("<YOUR_DOMAIN>") && PathPrefix("/dns-query")"
- "traefik.http.routers.dns-doh-secure.entrypoints=websecure"
- "traefik.http.routers.dns-doh-secure.service=dns-doh-svc"
- "traefik.http.routers.dns-doh-secure.tls=true"
- "traefik.http.routers.dns-doh-secure.tls.certresolver=cloudflare"
# --- TCP Router 3: DNS-over-TLS Endpoint (Port 853) ---
- "traefik.tcp.routers.dns-dot-secure.rule=HostSNI("<YOUR_DOMAIN>")"
- "traefik.tcp.routers.dns-dot-secure.entrypoints=dot"
- "traefik.tcp.routers.dns-dot-secure.tls=true"
- "traefik.tcp.routers.dns-dot-secure.tls.certresolver=cloudflare"
- "traefik.tcp.routers.dns-dot-secure.service=dns-dot-svc"
# --- Service Definitions ---
- "traefik.http.services.dns-dashboard-svc.loadbalancer.server.port=5380" # Web UI
- "traefik.http.services.dns-doh-svc.loadbalancer.server.port=8053" # DoH Protocol
- "traefik.tcp.services.dns-dot-svc.loadbalancer.server.port=53" # DoT Protocol (Traefik decrypts and sends to TCP 53) Detailed Configuration Breakdown
1. Networking Ports
Standard DNS runs on UDP and TCP port 53. Because this container is bound directly to the host's port 53, it acts as a primary network resolver. We map:
53:53/udp: For fast, standard DNS queries.53:53/tcp: For larger queries, zone transfers, and fallback.
2. Forwarding Protocol: DNS-over-QUIC
We set DNS_SERVER_FORWARDER_PROTOCOL=Quic. DNS-over-QUIC (DoQ) is a cutting-edge protocol that utilizes UDP rather than TCP for transport layer encryption. Compared to DNS-over-TLS (DoT), DoQ eliminates head-of-line blocking and establishes connections much faster, resulting in noticeably quicker web browsing.
3. Traefik Routing Configuration
Traefik handles SSL termination using Cloudflare ACME challenge (Let's Encrypt certificates):
- Web Admin Panel: Routed from
<YOUR_DOMAIN>on port443to Technitium's internal port5380. - DNS-over-HTTPS (DoH): Routed via
https://<YOUR_DOMAIN>/dns-query. Traefik routes this specifically to internal port8053(Technitium's default DoH service port). - DNS-over-TLS (DoT): Routed on port
853using a Traefik TCP router. Traefik performs the TLS decryption using the wildcard certificate and passes the raw DNS TCP stream to Technitium's port53.
Step-by-Step Installation
Step 1: Create Directories and Run the Container
Create the configuration and log directories on your host system to ensure data persistence:
mkdir -p config logs
docker compose up -d
Verify that the services are active and ports 53, 853, and 5380 are listening:
docker compose ps
ss -tulpn | grep -E '53|853'
Step 2: Access the Technitium Web Console
Navigate to your dashboard URL:
https://<YOUR_DOMAIN> To configure the server:
1. Log in Log in using the admin password configured in your environment file.
2. Open Blocking Settings In the top navigation, click on the Settings tab, and select Blocking.
3. Add the Blocklist Under the Allow / Block List URLs section, click Add and enter the Steven Black unified hosts file URL to block ads, fakenews, gambling, and pornography:
https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn/hosts 4. Block Roblox To block Roblox, click on the Blocked tab in the top navigation menu and add the following domains to the block list:
*.roblox.com
*.rbxcdn.com 5. Save and Apply Click Save Settings (if configuring under Settings) or apply the changes to ensure the block list is active.
Upstream Settings
Ensure that under Settings > Forwarding, your NextDNS forwarder address is active and utilizing DNS-over-QUIC. You can test your connection speed directly from the Technitium UI.
Client Device Configuration
Once your self-hosted DNS filter is online and public, you can configure your devices to utilize it.
Method A: Android Private DNS (DNS-over-TLS)
Android devices support system-wide DNS encryption natively.
- Open Settings on your Android device.
- Navigate to Network & Internet > Private DNS.
- Select Private DNS provider hostname.
- Enter your domain:
<YOUR_DOMAIN> - Save. All network traffic will now be securely filtered by your server.
Method B: Standard IPv4 Configuration
For devices, routers, or operating systems that do not support DoH/DoT directly:
- Configure the primary DNS server IP address to your server's public IP:
155.133.23.126. - (Optional) Configure a secondary DNS server to a fallback resolver, or keep it blank to ensure strict parental control enforcement.
Conclusion
By caching DNS requests locally and encrypting upstream traffic via DNS-over-QUIC, you establish a fast, private, and secure filtering system that circumvents commercial limits. Your home network is now shielded from malicious categories, pornography, gambling, and games without worrying about query counters.
Have questions about setting up Traefik or Technitium? Drop a comment or reach out via our Contact Us form.