Knot DNS and NSD as a Hidden Primary

Configure Knot DNS or NSD as a hidden primary that feeds an external secondary over AXFR.

The idea in short

A hidden primary keeps the master copy of your zone but is not listed in the zone's NS records. Only your secondary talks to it: the primary sends a NOTIFY when the zone changes, and the secondary pulls the zone with AXFR or IXFR. Knot DNS and NSD are both small, fast, authoritative-only servers, which makes them a good fit for this job.

The examples use the transfer addresses of hiddenprimary.ch. Two hosts can connect to your primary: the transfer node and the standby that takes over when the transfer node is unavailable. Allow both, each with its IPv4 and IPv6 address. If you use a different secondary, put its addresses there instead.

Knot DNS

1. Define the secondary and who may transfer

In Knot, a remote is a server you send messages to, and an acl decides who may ask you for something. You need both: remotes for NOTIFY, an ACL for the transfer.

knot.conf
remote:
  - id: secondary-main
    address: 159.69.29.118
  - id: secondary-standby
    address: 45.131.252.44
 
acl:
  - id: secondary-transfer
    address: [159.69.29.118, 2a01:4f8:1c0c:63c4::118, 45.131.252.44, 2a11:8b80:1000:1::18]
    action: transfer
 
zone:
  - domain: example.ch
    file: example.ch.zone
    notify: [secondary-main, secondary-standby]
    acl: secondary-transfer

2. Add a TSIG key (recommended)

With a key, a transfer request without the right signature is refused, whatever address it comes from. Add the key and reference it from the remotes and the ACL:

knot.conf
key:
  - id: example-transfer
    algorithm: hmac-sha256
    secret: <base64 secret>
 
# then add "key: example-transfer" to both remotes and to the acl

If an ACL has both address and key, a request must match both. Generate the secret with keymgr -t example-transfer hmac-sha256, or see the TSIG guide.

3. Reload and change zones

terminal
$ kzonecheck -o example.ch example.ch.zone
$ systemctl reload knot

Every time you edit the zone file, increase the SOA serial before you reload. Knot sends the NOTIFY on its own when it loads a higher serial. If you edit the zone through Knot's control interface instead of the file, Knot raises the serial for you.

NSD

1. Allow the transfer and set the notify targets

In NSD, provide-xfr says who may transfer the zone and notify says who receives a NOTIFY. Put both in a pattern, so every zone can reuse it. NOKEY means no TSIG key.

nsd.conf
pattern:
  name: "to-secondary"
  notify: 159.69.29.118 NOKEY
  notify: 45.131.252.44 NOKEY
  provide-xfr: 159.69.29.118 NOKEY
  provide-xfr: 2a01:4f8:1c0c:63c4::118 NOKEY
  provide-xfr: 45.131.252.44 NOKEY
  provide-xfr: 2a11:8b80:1000:1::18 NOKEY
 
zone:
  name: "example.ch"
  zonefile: "example.ch.zone"
  include-pattern: "to-secondary"

2. Add a TSIG key (recommended)

Define the key once and put its name in place of NOKEY:

nsd.conf
key:
  name: "example-transfer"
  algorithm: hmac-sha256
  secret: "<base64 secret>"
 
# in the pattern
  provide-xfr: 159.69.29.118 example-transfer

3. Check, reload, and change zones

terminal
$ nsd-checkconf /etc/nsd/nsd.conf
$ nsd-checkzone example.ch /etc/nsd/example.ch.zone
$ nsd-control reconfig
$ nsd-control reload example.ch

reconfig reads the changed nsd.conf. reload reads the zone file. NSD sends the NOTIFY when it loads a higher serial, so increase the serial on every edit.

Firewall

  • Inbound TCP and UDP port 53 from the transfer addresses: the secondary checks your SOA over UDP and transfers the zone over TCP.
  • Outbound UDP port 53 to the notify addresses.

Verify

Ask the secondary for a record you just changed. Compare the content, not only the serial: a secondary that signs the zone with DNSSEC uses its own serial.

terminal
$ dig +short A www.example.ch @ns1.hiddenprimary.ch

Next Steps