Safely Editing a Knot DNS Zone File (and How It Differs from BIND)

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-check or zone-reload fails, keep the zone frozen, fix the file and try again. Do not thaw a zone whose new file did not load successfully.

With zonefile-sync: -1, zone-flush requires the -f option. Do not add it blindly: it may overwrite a zone file that is intentionally kept as an input-only source.

Why don’t we 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 I keep the editing window short.

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 I am about to edit now represents the version Knot was serving when I froze it.

3. Edit the source file

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

The zone uses the standard textual DNS master-file format. I make the intended record change and increment the SOA serial unless zonefile-load is set to difference-no-serial. The serial tells secondaries that a newer version is available; recursive caches expire records according to their TTL, not the SOA serial.

Before saving, I 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 and performs the enabled semantic checks. It does not prove that I changed the right record or even the right zone; that still requires reading 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.

6. Resume automatic events

knotc -b zone-thaw example.com

zone-thaw unfreezes the zone and allows held events to run again. If automatic DNSSEC signing is configured, signing can continue.

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

Verify what is actually being served

First I 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
dig @127.0.0.1 example.com SOA +norecurse

If I want to be especially thorough, I query the zone’s authoritative servers directly. 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 I check a recursive resolver:

dig @1.1.1.1 example.com TXT +dnssec

I 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 I query a validating recursive resolver, I also look for the ad flag in the response.

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 /etc/bind/db.example.com
named-checkzone example.com /etc/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.

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 static BIND primary zone that named never changes, there may be no journal to synchronize and no dynamic updates to freeze. 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, I 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 I change the upstream primary or source instead of editing the transferred local copy.

Sources

Tags: