Install
# Debian / Ubuntu
sudo apt install knot
# Fedora / RHEL
sudo dnf install knot
# Verify
knotd --version
knotc --help
The minimum-viable config
Edit /etc/knot/knot.conf:
server:
listen: [ 0.0.0.0@53, ::@53 ]
user: knot:knot
log:
- target: syslog
any: info
template:
- id: default
storage: /var/lib/knot
file: "%s.zone" # zone file named after the zone (e.g. example.com.zone)
semantic-checks: on
dnssec-signing: on
dnssec-policy: default
dnssec-policy:
- id: default
algorithm: ecdsap256sha256
ksk-size: 256
zsk-size: 256
ksk-lifetime: 0 # never expire KSK (manually rotate)
zsk-lifetime: 30d
propagation-delay: 1h
rrsig-lifetime: 14d
rrsig-refresh: 7d
nsec3: on
nsec3-iterations: 0 # modern default; iterations is harmful
nsec3-opt-out: off
zone:
- domain: example.com
template: default
notify: secondaries
acl: [ secondaries-xfr ]
- domain: lab.example.com
template: default
remote:
- id: secondary-1
address: 192.0.2.10@53
acl:
- id: secondaries-xfr
address: [ 192.0.2.10 ]
action: transfer
- id: localhost
address: [ 127.0.0.1, ::1 ]
action: [ notify, refresh, update ]
Create the zone file
Drop /var/lib/knot/example.com.zone:
$ORIGIN example.com.
$TTL 3600
@ IN SOA ns1.example.com. hostmaster.example.com. (
2026052201 ; serial (YYYYMMDDnn)
3600 ; refresh
1800 ; retry
604800 ; expire
300 ; minimum TTL
)
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
ns1 IN A 192.0.2.5
ns2 IN A 192.0.2.6
@ IN A 203.0.113.10
www IN A 203.0.113.10
mail IN A 203.0.113.20
@ IN MX 10 mail
@ IN TXT "v=spf1 ip4:203.0.113.0/24 -all"
api IN A 203.0.113.30
api IN AAAA 2001:db8::30
Start it
sudo systemctl enable --now knot
sudo systemctl status knot
# Verify the zone is loaded + signed
sudo knotc zone-status example.com
# View the live zone (including DNSSEC RRSIGs)
sudo knotc zone-read example.com
# Verify with dig from another host
dig +dnssec @<your-server> example.com soa
If DNSSEC is configured (default in the template above), Knot auto-generates KSK + ZSK on first start, signs the zone, and uses NSEC3 for denial-of-existence proofs. Output of knotc zone-status shows the DNSKEY records.
Reload after zone changes
# Edit zone file, then bump the SOA serial (Knot won't reload otherwise)
sudo $EDITOR /var/lib/knot/example.com.zone
# Reload
sudo knotc zone-reload example.com
# Or for all zones
sudo knotc reload
DNSSEC: parent zone setup
Get the DS records to upload to the parent zone (your registrar):
sudo knotc zone-dnskey-set example.com
# Shows DNSKEY records (in the zone) and DS records (for the parent)
# Or use kdig to query directly
kdig @localhost example.com dnskey
kdig @localhost example.com ds
Submit the DS records to the registrar. After the parent publishes them, run an online DNSSEC verifier (e.g. dnsviz.net) to confirm the chain validates from the root.
Dynamic updates (DDNS)
For programmatic updates (cert-manager / cloudflared / scripted A-record updates):
acl:
- id: ddns-update
address: [ 127.0.0.1, 10.0.0.0/8 ]
action: update
zone:
- domain: dyn.example.com
template: default
acl: [ ddns-update ]
# Then use nsupdate to add records dynamically
nsupdate -k /etc/knot/key.conf
> server 127.0.0.1
> zone dyn.example.com
> update add host1.dyn.example.com 60 A 10.0.5.50
> send
Zone transfers to secondaries
For HA, run a second Knot (or other server) as secondary; primary auto-notifies on changes:
# On secondary
zone:
- domain: example.com
master: primary-1
file: "%s.zone"
serial-policy: increment
remote:
- id: primary-1
address: <primary-ip>@53
acl:
- id: from-primary
address: [ <primary-ip> ]
action: [ notify ]
kdig: the better dig
Knot ships kdig as a replacement for dig with cleaner output + better DNSSEC visualization:
kdig @ns1.example.com example.com soa +dnssec
kdig -t any example.com
kdig -x 8.8.8.8 # reverse lookup
kdig +trace example.com # walk the chain from the root
Drop-in for dig in most cases; output is more readable for DNSSEC-heavy zones.
Catalog zones (RFC 9432)
For "I have 200 small zones; managing each by hand is annoying":
# A catalog zone lists the member zones
zone:
- domain: catalog.example.
catalog-role: generate
catalog-template: default
file: "catalog.zone"
The catalog zone is itself a zone with PTR records for each member zone. Add a member by adding a PTR; Knot auto-creates the zone in memory + signs it. Useful for hosting providers with many customer zones.
Knot vs PowerDNS
- Knot — primarily file-based; lean; fast; CZ.NIC pedigree. Less of an ecosystem for programmatic management.
- PowerDNS (see that tutorial) — database-backed by default; REST API; richer ecosystem (PowerDNS-Admin UI, integrations).
Pick by workflow: for "I commit zone files to git + reload," Knot. For "I want a REST API to programmatically add records," PowerDNS.
Knot vs BIND
BIND is the elder; massive feature surface; correspondingly more knobs + larger attack surface. Knot is the modern, lean alternative; runs at ccTLD scale without BIND's operational quirks.
For recursion (not authoritative): Knot Resolver
Confusingly, Knot DNS (authoritative) and Knot Resolver (recursive) are different products. For "I want a recursive resolver for my LAN" (the role of Unbound / Pi-hole's backend), use Knot Resolver instead.
For "I want to be the authoritative server for my own domains," this tutorial.