{"id":5870,"date":"2026-06-12T09:30:46","date_gmt":"2026-06-12T13:30:46","guid":{"rendered":"https:\/\/dft.wiki\/?p=5870"},"modified":"2026-06-14T09:21:33","modified_gmt":"2026-06-14T13:21:33","slug":"ha-dns-with-technitium-plus-dnssec","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=5870","title":{"rendered":"DNS: HA plus Hidden Primary With Technitium"},"content":{"rendered":"<p><strong>Technitium DNS Server<\/strong> is an open-source DNS solution that combines recursive and authoritative resolvers [<a href=\"https:\/\/github.com\/TechnitiumSoftware\/DnsServer\">Link<\/a>].<\/p>\n<p>Besides the extensions\/plugins, Technitium is a monolithic (C#) application with an integrated web GUI (that is the biggest difference when compared with <strong>PowerDNS<\/strong>).<\/p>\n<p>In previous posts, I introduced the whole <strong>PowerDNS<\/strong> stack [<a href=\"https:\/\/dft.wiki\/?p=5517\">Link<\/a>] and different design strategies for geographic resilience [<a href=\"https:\/\/dft.wiki\/?p=5539\">Link<\/a>].<\/p>\n<p>The purpose of this post is to introduce <strong>Technitium<\/strong> as a powerful, all-in-one DNS solution. It is not as mature as BIND, Unbound, DNSMasq, or even PowerDNS, but it arguably fills the gaps of all of them in a single package.<\/p>\n<p>Another highlight will be the resilient design built around the resolvers, using the &#8220;hidden primary&#8221; concept proposed in <strong>NIST SP 800-81r3 &#8211; Secure Domain Name System (DNS) Deployment Guide<\/strong> [<a href=\"https:\/\/nvlpubs.nist.gov\/nistpubs\/SpecialPublications\/NIST.SP.800-81r3.pdf\">Link<\/a>].<\/p>\n<hr \/>\n<p><strong>DESIGN<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5895\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Hidden-Primary-1.png\" alt=\"\" width=\"467\" height=\"370\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Hidden-Primary-1.png 467w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Hidden-Primary-1-300x238.png 300w\" sizes=\"auto, (max-width: 467px) 100vw, 467px\" \/><\/p>\n<p>Key points of this design:<\/p>\n<ul>\n<li>At the edge, the public IPs only serve the replicas (secondary) of the zones from the main (primary) server.<\/li>\n<li>The primary server can reside in any undisclosed location with no inbound traffic.<\/li>\n<li>A WireGuard mesh network (VPN) with strict ACLs allows the replicas to reach the primary to fetch changes.<\/li>\n<\/ul>\n<p>The key point is that the primary is not internet-facing, and all nodes have static addresses within the mesh network (VPN).<\/p>\n<p>Here are popular mesh network solutions:<\/p>\n<ul>\n<li><strong>Netbird<\/strong> [<a href=\"https:\/\/github.com\/netbirdio\/netbird\">Link<\/a>] &#8211; Recommended\n<ul>\n<li>Fully open-source and self-hostable,<\/li>\n<li>Also available as a managed service.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Nebula<\/strong> [<a href=\"https:\/\/github.com\/slackhq\/nebula\">Link<\/a>]\n<ul>\n<li>The mesh network is open-source, with a native orchestrator called <strong>Lighthouse<\/strong>.<\/li>\n<li>Many organizations offer managed Nebula with their own proprietary orchestrator.<\/li>\n<\/ul>\n<\/li>\n<li><strong>TailScale<\/strong> [<a href=\"https:\/\/github.com\/tailscale\/tailscale\">Link<\/a>]\n<ul>\n<li>Probably the most well-known managed mesh network,<\/li>\n<li>The client is open-source, but the official orchestrator is proprietary and cannot be self-hosted,<\/li>\n<li>There is an open-source orchestrator alternative called <strong>Headscale<\/strong> [<a href=\"https:\/\/github.com\/juanfont\/headscale\">Link<\/a>].<\/li>\n<\/ul>\n<\/li>\n<li><strong>ZeroTier<\/strong> [<a href=\"https:\/\/zerotier.com\/\">Link<\/a>]\n<ul>\n<li>Free for non-commercial use and source-available,<\/li>\n<li>Licensing limits commercial use, and managed service is only available through ZeroTier itself.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<p><strong>PRIMARY AUTHORITATIVE<\/strong><\/p>\n<p><strong>Installation<\/strong> &#8211; The easy way [<a href=\"https:\/\/technitium.com\/dns\/\">Link<\/a>].<\/p>\n<pre>curl -sSL https:\/\/download.technitium.com\/dns\/install.sh | sudo bash<\/pre>\n<p>5 seconds later&#8230; it is done!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5896\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-32-53.png\" alt=\"\" width=\"757\" height=\"427\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-32-53.png 757w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-32-53-300x169.png 300w\" sizes=\"auto, (max-width: 757px) 100vw, 757px\" \/><\/p>\n<p>Navigate to <strong>http:\/\/&lt;IP&gt;:5380<\/strong> and set a secure password for the <code>admin<\/code> account.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5897\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-34-11.png\" alt=\"\" width=\"1253\" height=\"1149\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-34-11.png 1253w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-34-11-300x275.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-34-11-1024x939.png 1024w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-34-11-768x704.png 768w\" sizes=\"auto, (max-width: 1253px) 100vw, 1253px\" \/><\/p>\n<p>In most organizations today, sysadmins prefer to deploy dedicated servers this way. While snapshots, backups, and geo-replication are still configured for data safety, high availability (HA) is handled by the replicas, not the primary server itself.<\/p>\n<p>Add the primary server to your mesh network of choice.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5898\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-45-21.png\" alt=\"\" width=\"785\" height=\"640\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-45-21.png 785w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-45-21-300x245.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-45-21-768x626.png 768w\" sizes=\"auto, (max-width: 785px) 100vw, 785px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5899\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-49-14.png\" alt=\"\" width=\"565\" height=\"245\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-49-14.png 565w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-49-14-300x130.png 300w\" sizes=\"auto, (max-width: 565px) 100vw, 565px\" \/><\/p>\n<p>It will immediately start the recursive resolver. See the default recursion setting below.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5901\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-57-03.png\" alt=\"\" width=\"949\" height=\"911\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-57-03.png 949w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-57-03-300x288.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-57-03-768x737.png 768w\" sizes=\"auto, (max-width: 949px) 100vw, 949px\" \/><\/p>\n<p>Note the real-time metrics.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5902\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-44.png\" alt=\"\" width=\"459\" height=\"222\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-44.png 459w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-44-300x145.png 300w\" sizes=\"auto, (max-width: 459px) 100vw, 459px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5903\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-57.png\" alt=\"\" width=\"461\" height=\"463\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-57.png 461w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-57-300x300.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_22-58-57-150x150.png 150w\" sizes=\"auto, (max-width: 461px) 100vw, 461px\" \/><\/p>\n<p><strong>Creating a New Zone<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5904\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-22.png\" alt=\"\" width=\"953\" height=\"632\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-22.png 953w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-22-300x199.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-22-768x509.png 768w\" sizes=\"auto, (max-width: 953px) 100vw, 953px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5905\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-48.png\" alt=\"\" width=\"789\" height=\"535\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-48.png 789w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-48-300x203.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-00-48-768x521.png 768w\" sizes=\"auto, (max-width: 789px) 100vw, 789px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5906\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-01-04.png\" alt=\"\" width=\"949\" height=\"943\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-01-04.png 949w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-01-04-300x298.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-01-04-150x150.png 150w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-01-04-768x763.png 768w\" sizes=\"auto, (max-width: 949px) 100vw, 949px\" \/><\/p>\n<p>Check the address range of your mesh network. NetBird uses <strong>100.69.0.0\/16<\/strong>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5907\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-03-16.png\" alt=\"\" width=\"850\" height=\"61\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-03-16.png 850w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-03-16-300x22.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-03-16-768x55.png 768w\" sizes=\"auto, (max-width: 850px) 100vw, 850px\" \/><\/p>\n<p>Open the advanced options for the zone.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5908\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-10-22.png\" alt=\"\" width=\"650\" height=\"201\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-10-22.png 650w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-13_23-10-22-300x93.png 300w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>Allow query access to the entire mesh network address space. Fine-grained access control can be handled at the mesh network level using policies.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5912\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-15-24.png\" alt=\"\" width=\"793\" height=\"667\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-15-24.png 793w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-15-24-300x252.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-15-24-768x646.png 768w\" sizes=\"auto, (max-width: 793px) 100vw, 793px\" \/><\/p>\n<p>Allow zone transfer to the replicas.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5913\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-14-01.png\" alt=\"\" width=\"793\" height=\"667\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-14-01.png 793w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-14-01-300x252.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-14-01-768x646.png 768w\" sizes=\"auto, (max-width: 793px) 100vw, 793px\" \/><\/p>\n<p>Leave the zone for now and configure the replicas.<\/p>\n<hr \/>\n<p><strong>SECONDARY AUTHORITATIVE<\/strong><\/p>\n<p>The same installation method used for the primary can be used for the secondaries, but for this setup we will use containers in a more ephemeral fashion. This approach offers more flexibility for scaling on demand and can be deployed fresh from source at any time.<\/p>\n<p><strong>Mesh Network<\/strong><\/p>\n<p>Many mesh networks, such as NetBird, include their own internal DNS service. After adding the secondary instances to the network, group them all together.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5914\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-02.png\" alt=\"\" width=\"981\" height=\"519\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-02.png 981w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-02-300x159.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-02-768x406.png 768w\" sizes=\"auto, (max-width: 981px) 100vw, 981px\" \/><\/p>\n<p>Then disable DNS management for the group of resolvers (named &#8220;DNS&#8221; in this example).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5915\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-17.png\" alt=\"\" width=\"850\" height=\"554\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-17.png 850w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-17-300x196.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-34-17-768x501.png 768w\" sizes=\"auto, (max-width: 850px) 100vw, 850px\" \/><\/p>\n<p>Create a policy that allows traffic between DNS instances on port 53 over <strong>UDP<\/strong>, and another for <strong>TCP<\/strong>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5916\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-53-27.png\" alt=\"\" width=\"775\" height=\"691\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-53-27.png 775w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-53-27-300x267.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_07-53-27-768x685.png 768w\" sizes=\"auto, (max-width: 775px) 100vw, 775px\" \/><\/p>\n<p><strong>Installation<\/strong><\/p>\n<pre>sudo apt install docker.io docker-compose -y\r\nsudo systemctl disable --now systemd-resolved\r\nsudo rm -f \/etc\/resolv.conf\r\necho 'nameserver 1.1.1.1' | sudo tee \/etc\/resolv.conf\r\necho 'search internal' | sudo tee -a \/etc\/resolv.conf<\/pre>\n<p>The official documentation provides a Docker Compose template, but it is not complete for this deployment.<\/p>\n<pre>wget https:\/\/raw.githubusercontent.com\/TechnitiumSoftware\/DnsServer\/refs\/heads\/master\/docker-compose.yml\r\nsudo docker compose up -d<\/pre>\n<p>Instead, create a <code>docker-compose.yml<\/code> file with the following content.<\/p>\n<pre>services:\r\n  dns-server:\r\n    container_name: dns-server\r\n    hostname: dns-server\r\n    image: docker.io\/technitium\/dns-server:latest\r\n    ports:\r\n      - \"5380:5380\/tcp\"\r\n      - \"53:53\/udp\"\r\n      - \"53:53\/tcp\" \r\n    environment:\r\n      - DNS_SERVER_DOMAIN=dns-server\r\n      - DNS_SERVER_ADMIN_PASSWORD=<strong>ChangeMe_StrongPassword<\/strong>\r\n      - DNS_SERVER_RECURSION=Deny\r\n      - DNS_SERVER_LOG_FOLDER_PATH=\/var\/log\/technitium\/dns\r\n    volumes:\r\n      - config:\/etc\/dns\r\n      - logs:\/var\/log\/technitium\/dns\r\n    restart: unless-stopped\r\n    sysctls:\r\n      - net.ipv4.ip_local_port_range=1024 65535\r\n  zone-init:\r\n    image: docker.io\/curlimages\/curl:latest\r\n    container_name: dns-zone-init\r\n    depends_on:\r\n      - dns-server\r\n    restart: \"no\"\r\n    environment:\r\n      - DNS_URL=http:\/\/dns-server:5380\r\n      - DNS_USER=admin\r\n      - DNS_PASS=<strong>ChangeMe_StrongPassword<\/strong>     # must match DNS_SERVER_ADMIN_PASSWORD above\r\n      - PRIMARY_NS=<strong>100.69.25.251<\/strong>             # primary server holding the master zone(s)\r\n      - ZONE_TYPE=Secondary                  # use SecondaryCatalog to auto-pull ALL zones\r\n      - ZONE_NAMES=<strong>example.com<\/strong>               # comma-separated list of zones to replicate\r\n    entrypoint: [\"\/bin\/sh\", \"-c\"]\r\n    command:\r\n      - |\r\n        set -eu\r\n        echo \"Waiting for Technitium API ...\"\r\n        until TOKEN=$$(curl -sf \"$${DNS_URL}\/api\/user\/login?user=$${DNS_USER}&amp;pass=$${DNS_PASS}\" | sed -n 's\/.*\"token\":\"\\([^\"]*\\)\".*\/\\1\/p'); [ -n \"$${TOKEN}\" ]; do\r\n          sleep 3\r\n        done\r\n        echo \"Authenticated.\"\r\n\r\n        IFS=','\r\n        for ZONE in $${ZONE_NAMES}; do\r\n          ZONE=$$(echo \"$${ZONE}\" | tr -d ' ')\r\n          [ -z \"$${ZONE}\" ] &amp;&amp; continue\r\n          echo \"Creating $${ZONE_TYPE} zone $${ZONE} (primary $${PRIMARY_NS})\"\r\n          curl -s \"$${DNS_URL}\/api\/zones\/create?token=$${TOKEN}&amp;zone=$${ZONE}&amp;type=$${ZONE_TYPE}&amp;primaryNameServerAddresses=$${PRIMARY_NS}\"\r\n          echo\r\n        done\r\nvolumes:\r\n    config:\r\n    logs:<\/pre>\n<p><strong>Explanation<\/strong><\/p>\n<ul>\n<li>The <code>dns-server<\/code> container runs Technitium with:\n<ul>\n<li>Recursion disabled (authoritative only),<\/li>\n<li>A custom password set for API access.<\/li>\n<\/ul>\n<\/li>\n<li>The <code>zone-init<\/code> container is a sidecar that:\n<ul>\n<li>Automatically creates the secondary zone(s),<\/li>\n<li>Runs once on startup and then exits.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<p><strong>APPLYING THE NAMESERVERS<\/strong><\/p>\n<ul>\n<li><strong>Primary<\/strong>\n<ul>\n<li>Deployed in an undisclosed location (&#8220;hidden primary&#8221; concept),<\/li>\n<li>No public IP, only accessible via a private network for zone transfer.<\/li>\n<\/ul>\n<\/li>\n<li>Secondary <strong>NS1<\/strong>\n<ul>\n<li>Deployed on Digital Ocean (just an example):\n<ul>\n<li><code>104.248.10.10<\/code><\/li>\n<li><code>2604:a880::1<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Secondary <strong>NS2<\/strong>\n<ul>\n<li>Deployed on Linode (just an example):\n<ul>\n<li><code>139.162.0.1<\/code><\/li>\n<li><code>2a01:7e00::1<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Make changes to the zone following the example below.<\/p>\n<p><strong>NS<\/strong>, <strong>A<\/strong>, and <strong>AAAA<\/strong> records must be present for both <strong>NS1<\/strong> and <strong>NS2<\/strong>, with no evidence of the hidden primary.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5917\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-00-15.png\" alt=\"\" width=\"911\" height=\"739\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-00-15.png 911w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-00-15-300x243.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-00-15-768x623.png 768w\" sizes=\"auto, (max-width: 911px) 100vw, 911px\" \/><\/p>\n<p>Changes will not propagate from the primary to the secondaries immediately. If you do not want to wait 15 minutes (900 seconds) for changes to appear on the replicas, enable notify.<\/p>\n<p>On the Primary:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5919\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-47-05.png\" alt=\"\" width=\"789\" height=\"665\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-47-05.png 789w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-47-05-300x253.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-47-05-768x647.png 768w\" sizes=\"auto, (max-width: 789px) 100vw, 789px\" \/><\/p>\n<p>On the Secondaries:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5920\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-51-54.png\" alt=\"\" width=\"791\" height=\"663\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-51-54.png 791w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-51-54-300x251.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_08-51-54-768x644.png 768w\" sizes=\"auto, (max-width: 791px) 100vw, 791px\" \/><\/p>\n<p>Finally, add the NS records to your registrar.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5921\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-02-02.png\" alt=\"\" width=\"762\" height=\"411\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-02-02.png 762w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2026\/06\/Screenshot_2026-06-14_09-02-02-300x162.png 300w\" sizes=\"auto, (max-width: 762px) 100vw, 762px\" \/><\/p>\n<p>It may take some time to take effect. Be patient.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Technitium DNS Server is an open-source DNS solution that combines recursive and authoritative resolvers [Link]. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5870","post","type-post","status-publish","format-standard","hentry","category-ccna"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/5870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5870"}],"version-history":[{"count":11,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/5870\/revisions"}],"predecessor-version":[{"id":5923,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/5870\/revisions\/5923"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}