TTR Networks

Intermediate · PowerDNS on Debian: authoritative, secondary, DNSSEC and recursor · section 6 of 10

A root to recurse from

✓ Lab-tested 21 October 2026 on Debian 13.7, PowerDNS Authoritative 4.9.17, PowerDNS Recursor 5.2.13, BIND dig 9.20.29

A recursive resolver starts every lookup at the root of the DNS, so the lab needs a root to start from. The real root and TLD servers aren't reachable from a Docker lab, and you'd never want a lab to touch them anyway, so one more PowerDNS server, rootns, plays both parts.

It hosts two zones, built with the same pdnsutil commands as before:

  • The root zone, ., which delegates net to the TLD server.
  • The net zone, which delegates example.net to ns1 and ns2. Because those servers' names are inside example.net itself, the net zone also carries their addresses (glue), or no resolver could ever find them.

The server names use .test, a top-level domain reserved for testing, so nothing in the lab pretends to be a real root server.

Asked about www.example.net without recursion, the lab root does exactly what the real net servers would: it doesn't answer, but refers the client to ns1 and ns2, with their glue addresses in the additional section. Following those referrals from the root down is precisely what the recursor will do.

The lab's root and net zones (real output)
root@rootns:~# pdnsutil create-zone . ns.root.test >/dev/null && pdnsutil replace-rrset . @ SOA 86400 "ns.root.test. hostmaster.root.test. 2026102101 1800 900 604800 86400" >/dev/null && pdnsutil add-record . ns.root.test A 203.0.113.1 >/dev/null && pdnsutil add-record . net NS ns.tld.test >/dev/null && pdnsutil add-record . ns.tld.test A 203.0.113.1 >/dev/null; pdnsutil create-zone net ns.tld.test >/dev/null && pdnsutil replace-rrset net @ SOA 86400 "ns.tld.test. hostmaster.tld.test. 2026102101 1800 900 604800 86400" >/dev/null && pdnsutil add-record net example NS ns1.example.net >/dev/null && pdnsutil add-record net example NS ns2.example.net >/dev/null && pdnsutil add-record net ns1.example A 203.0.113.53 >/dev/null && pdnsutil add-record net ns2.example A 203.0.113.54 >/dev/null; systemctl restart pdns
Creating empty zone '.'
Creating empty zone 'net'

root@rootns:~# pdnsutil list-zone .; pdnsutil list-zone net
$ORIGIN .
.	3600	IN	NS	ns.root.test.
.	86400	IN	SOA	ns.root.test hostmaster.root.test 2026102101 1800 900 604800 86400
net	3600	IN	NS	ns.tld.test.
ns.root.test	3600	IN	A	203.0.113.1
ns.tld.test	3600	IN	A	203.0.113.1
$ORIGIN .
example.net	3600	IN	NS	ns1.example.net.
example.net	3600	IN	NS	ns2.example.net.
net	3600	IN	NS	ns.tld.test.
net	86400	IN	SOA	ns.tld.test hostmaster.tld.test 2026102101 1800 900 604800 86400
ns1.example.net	3600	IN	A	203.0.113.53
ns2.example.net	3600	IN	A	203.0.113.54

root@client:~# dig @203.0.113.1 www.example.net +norecurse

; <<>> DiG 9.20.29-1~deb13u1-Debian <<>> @203.0.113.1 www.example.net +norecurse
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6561
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.example.net.		IN	A

;; AUTHORITY SECTION:
example.net.		3600	IN	NS	ns1.example.net.
example.net.		3600	IN	NS	ns2.example.net.

;; ADDITIONAL SECTION:
ns2.example.net.	3600	IN	A	203.0.113.54
ns1.example.net.	3600	IN	A	203.0.113.53

;; Query time: 1 msec
;; SERVER: 203.0.113.1#53(203.0.113.1) (UDP)
;; WHEN: Wed Oct 21 05:44:13 UTC 2026
;; MSG SIZE  rcvd: 112
  • Lines 7–9: The root: its own nameserver, and a delegation of net.
  • Lines 10–11: Addresses for the root and net servers (both 203.0.113.1 in the lab).
  • Lines 13–14: The net zone delegates example.net to ns1 and ns2…
  • Lines 17–18: …with glue: their addresses, which live inside the zone being delegated.
  • Lines 26–27: No answer (aa isn't set), but authority…
  • Lines 35–40: …a referral to ns1 and ns2, with their glue addresses.