Editing a Knot DNS Zone File

Knot normally serves a live zone from memory, and DDNS or DNSSEC signing may make that in-memory state newer than the zone file on disk. I wrote this note so I do not have to work out the safe editing procedure again next time.

TL;DR

This procedure assumes a locally maintained primary zone whose configured zone file is loaded by Knot and can be synchronized from the live zone. It does not apply unchanged to a secondary, a zonefileless configuration such as zonefile-load: none, or a configuration that deliberately disables zone-file synchronization with zonefile-sync: -1.

For a zone whose configured file is /var/lib/knot/zones/example.com.zone:

knotc -b zone-freeze example.com
knotc -b zone-flush example.com

vim /var/lib/knot/zones/example.com.zone

knotc zone-check example.com
knotc -b zone-reload example.com
knotc -b zone-thaw example.com

While editing the file, increment the SOA serial unless zonefile-load is set to difference-no-serial.

If zone-freeze fails, do not edit the file. If zone-flush fails — or is skipped because synchronization is disabled — the file may be stale, so stop until it is clear which copy is current.

If zone-check or zone-reload fails, leave the zone frozen, fix the file, and retry. To abandon the edit, restore the known-good pre-edit contents — under the synchronized-file assumptions above, by running knotc -b zone-flush example.com again — and only then thaw the zone. On a signed zone, keep this recovery window short because a freeze also holds DNSSEC re-signing.

With zonefile-sync: -1, even knotc -b zone-flush writes nothing, yet returns OK and exits 0. Knot emits a server-side zonefile synchronization disabled, use force command to override it warning, but knotc still reports success. To force a flush, use knotc -f -b zone-flush example.com. Do not add -f blindly: it may overwrite a zone file that is intentionally kept as an input-only source.

Why not just edit the zone file?

Normally, the live zone resides in memory, and Knot may change it automatically — for example, by renewing DNSSEC signatures or applying dynamic DNS updates. The file on disk may therefore lag behind the live zone.

The two directions to remember are:

live zone + journal  -- zone-flush -->  zone file on disk
zone file on disk    -- zone-reload --> live zone

zone-flush does not flush a DNS cache or transfer the zone to another server. It writes the current zone state to the configured zone file. That is why it belongs before the edit: running it after editing but before zone-reload could overwrite the changes in the file with the older state still held by Knot.

What each step does in more detail

1. Freeze automatic zone-changing events

knotc -b zone-freeze example.com

zone-freeze lets an already-running event finish, then holds new or pending events that would change the zone, including load, refresh, dynamic update, flush, and DNSSEC signing events.

It does not stop DNS service. The authoritative server continues answering from the current version of the zone. It also does not block outgoing AXFR or IXFR; zone-xfr-freeze controls outgoing transfers separately.

In Knot DNS 3.5, up to eight DDNS updates per zone are queued while the zone is frozen; subsequent updates are refused. The freeze state also does not persist across a server restart, so keep the editing window short.

A freeze is a holding pen, not a resting state: it also holds periodic DNSSEC re-signing, so a signed zone left frozen stops refreshing its RRSIGs. With the default rrsig-lifetime of 14 days, the signatures eventually expire. Answers that rely on expired signatures fail validation, and validating resolvers typically return SERVFAIL. If recovery is going to take a while, restore the known-good pre-edit contents as described above, thaw the zone so the currently loaded contents can keep being re-signed, and start again later.

zone-freeze is not an absolute lock against operator actions. Explicit commands such as zone-flush and zone-reload can still run while the zone is frozen. This is intentional; otherwise, the safe editing procedure would not work.

The -b option means blocking mode, not backup. Without it, OK may only mean that Knot accepted the request. With -b, knotc waits for the requested event to finish and can report a processing error.

2. Write the current zone to disk

knotc -b zone-flush example.com

This synchronizes the current live zone state, including journaled changes, into the configured zone file. The file now represents the version Knot was serving when the freeze completed.

3. Edit the source file

vim /var/lib/knot/zones/example.com.zone

The zone uses the standard textual DNS master-file format. Make the intended record change — for example, add an apex TXT record such as @ 300 IN TXT "google-site-verification=token" — and increment the SOA serial unless zonefile-load is set to difference-no-serial. The serial lets secondaries recognize that a newer version is available; recursive caches expire records according to their TTL, not the SOA serial.

Before saving, check the filename, the $ORIGIN or SOA owner, and the domain named in the change request. A syntactically valid edit to the wrong zone is still wrong.

4. Check the file

knotc zone-check example.com

This tests whether Knot can load the configured zone file. Mandatory semantic checks always run. The semantic-checks option, which is off by default, enables additional checks; warnings from those extra checks do not normally prevent the zone from loading. A clean result does not prove that the right record — or even the right zone — was changed; that still requires reviewing the diff and querying the result.

5. Load the edited file

knotc -b zone-reload example.com

zone-reload loads the edited file into the running zone. This changes the live zone, but an explicitly requested reload is allowed while the zone is frozen.

On a primary, a successful reload also schedules a NOTIFY event for configured secondaries. Because zone-freeze does not block outgoing AXFR or IXFR, secondary copies can start updating before zone-thaw.

6. Resume automatic events

knotc -b zone-thaw example.com

zone-thaw unfreezes the zone and allows held events to run again. With automatic DNSSEC signing, the records loaded in step 5 are signed before the new zone becomes active — signing runs as part of the zone load — so the thaw only releases any held DNSSEC signing and the other held events.

A successful blocking thaw proves that the thaw operation finished. It does not prove that every event released by the thaw, such as DNSSEC signing or refresh, has also finished, so verify the resulting zone separately.

Verify what is actually being served

First, check the local server, assuming this Knot instance listens on 127.0.0.1:

knotc zone-status example.com +serial +events +freeze
knotc zone-read example.com @ SOA
knotc zone-read example.com @ TXT
dig @127.0.0.1 example.com SOA +norecurse
dig @127.0.0.1 example.com TXT +norecurse +dnssec

The TXT queries match the apex record in step 3. For a different change, query the exact owner and record type affected by that change.

If I want to be especially thorough, I query the zone’s authoritative servers directly. In a primary-secondary setup, this also confirms whether the secondaries have transferred the new serial. For an imaginary setup with ns1.example.net and ns2.example.net:

dig @ns1.example.net example.com SOA +norecurse
dig @ns2.example.net example.com SOA +norecurse
dig @ns1.example.net example.com TXT +norecurse +dnssec
dig @ns2.example.net example.com TXT +norecurse +dnssec

In a conventional primary-secondary setup, the authoritative servers should return the expected records and, once transfers have completed, the same SOA serial. Finally, check a recursive resolver:

dig @1.1.1.1 example.com TXT +dnssec

Do not use +norecurse for this last query: unlike an authoritative server, a public recursive resolver may need to fetch the answer first.

+dnssec requests DNSSEC records by setting the DO bit; it does not validate the answer by itself. When querying a validating recursive resolver, also look for the ad flag in the response. On a signed zone, a positive answer for the edited RRset should also carry a covering RRSIG. Because Knot signs as part of a successful zone load, a missing RRSIG after a blocking reload is not an expected “signing has not caught up yet” state; confirm that the intended signed zone and server were queried, then inspect the DNSSEC configuration and server log.

These checks answer different questions. A localhost query shows what this Knot instance is serving. Direct authoritative queries show what those servers are serving. A recursive query shows what clients can currently obtain, possibly from a cache.

How this compares with BIND

For a dynamically updated BIND primary zone, the familiar workflow is shorter:

rndc freeze example.com

# Edit records and increment the SOA serial.
vim /var/lib/bind/db.example.com
named-checkzone example.com /var/lib/bind/db.example.com

rndc thaw example.com

rndc freeze refuses dynamic updates and synchronizes journal changes into the master file. rndc thaw reloads the edited file and enables dynamic updates again. A dynamically updated zone must use a directory where named can write its zone and journal files. With the stock Debian and Ubuntu packaging, /var/lib/bind is the conventional location; /etc/bind is normally kept read-only by the packaged AppArmor profile unless it is customized.

The rough mapping is therefore:

Purpose Knot BIND dynamic zone
Prepare a changing zone for manual file editing zone-freeze + zone-flush rndc freeze
Check the edited file knotc zone-check named-checkzone
Load the file and resume changes zone-reload + zone-thaw rndc thaw

For a BIND primary with neither dynamic updates nor automated signing, there is normally no journal to synchronize and nothing to freeze. For such a zone, rndc freeze fails with rndc: 'freeze' failed: not dynamic, and the usual procedure is simply:

# Edit records and increment the SOA serial.
vim /etc/bind/db.example.com
named-checkzone example.com /etc/bind/db.example.com
rndc reload example.com

With inline DNSSEC signing, edit the configured unsigned source file, not generated .signed or .jnl files.

The exact procedure therefore depends less on the DNS server software than on whether the live zone can be modified only by the administrator or also by DDNS and an online DNSSEC signer. A secondary obtains its zone through a transfer, so change the upstream primary or source instead of editing the transferred local copy.

Sources

Tags: