Ubuntu 22.04 安装 Knot DNS 指南

Ubuntu 22.04 宿主 systemd 形态安装 Knot DNS 实战:发行版仓库与 CZ.NIC 官方仓库双方案实测、首次配置闭环、版本升降级与五类排障实录(53 端口冲突、confdb 机制、reload 语义等),卸载清理还原。

Knot DNSKnotDNS2026/10/20

Ubuntu 22.04 安装 Knot DNS 指南

目标:在 Ubuntu 22.04 LTS 服务器上安装并运行 Knot DNS 权威域名服务器,覆盖三种安装方案(发行版仓库 / CZ.NIC 官方仓库 / 源码编译)、首次配置闭环、版本升降级与卸载清理。本文全部命令与输出均在目标环境逐条实测,回显逐行照抄(运行环境为 22.04.4 LTS,内核口径见环境信息节),可直接照做。

一、环境信息

项目值
操作系统Ubuntu 22.04.4 LTS(jammy),x86_64
测试版本Knot DNS 3.6.1(CZ.NIC 官方仓库包名 3.6.1-cznic.1~jammy)
发行版仓库版本knot 3.1.6-1ubuntu1(jammy/universe,2021 年版本,仅作对照)
安装形态Ubuntu 宿主直装,systemd 管理(knot.service)
服务端口DNS 53/UDP+TCP(本机被占用,见下)
控制套接字/run/knot/knot.sock(Unix socket,非 TCP)
主要路径配置 /etc/knot/knot.conf;数据 /var/lib/knot/;运行时 /run/knot/

端口占用说明(重要):装前对 53 端口做盘点(ss -ltn 快照,装前存档原文):

State  Recv-Q Send-Q      Local Address:Port  Peer Address:PortProcess
LISTEN 0      4096        127.0.0.53%lo:53         0.0.0.0:*

即装前 53/TCP 仅被 systemd-resolved 存根(127.0.0.53)占用。实测会话期间,本机另有其他 DNS 服务实例先后占用了 127.0.0.1:53 与 127.0.0.2:53(多服务共存的真实生产环境常态),导致 Knot 首次以 127.0.0.1@53 启动即失败(报错见 FAQ-1)。因此本文将 Knot 绑定到空闲回环地址 127.0.0.9@53 做实测。若你的服务器 53 端口干净,把配置里的 127.0.0.9@53 换成 0.0.0.0@53(或网卡 IP)即可,其余步骤完全一致。

二、前置条件

# 1) 更新软件包索引
sudo apt update
# 2) 安装基础工具(官方仓库接入需要 wget 与 https 支持)
sudo apt install -y apt-transport-https ca-certificates wget
# 3) 检查 53 端口现状,决定后续监听地址
ss -ltnup | grep ':53 '

实测回显(第 3 步,装前盘点):

udp   UNCONN 0      0            127.0.0.2:53        0.0.0.0:*    users:(("pdns_server",pid=1389970,fd=6))
udp   UNCONN 0      0            127.0.0.53%lo:53    0.0.0.0:*    users:(("systemd-resolve",pid=716,fd=13))
udp   UNCONN 0      0            127.0.0.1:53        0.0.0.0:*    users:(("nsd",pid=1410245,fd=100))
tcp   LISTEN 0      4096         127.0.0.53%lo:53    0.0.0.0:*    users:(("systemd-resolve",pid=716,fd=14))
tcp   LISTEN 0      128          127.0.0.2:53        0.0.0.0:*    users:(("pdns_server",pid=1389970,fd=7))
tcp   LISTEN 0      128          127.0.0.1:53        0.0.0.0:*    users:(("nsd",pid=1410245,fd=102))

💡 技术拓展:127.0.0.53 是 systemd-resolved 的存根监听(stub resolver)。宿主自装权威 DNS 时有两条路:① 保持存根,把权威服务绑定到具体地址(外网 IP 或专用回环地址);② 停用 resolved 的 DNSStubListener 并重启,释放全局 53。Knot 允许同一服务多监听(listen 列表),多 DNS 服务共存的机器务必先把「谁来监听哪个地址」规划清楚。

三、版本选型说明

三条获取路线,按需选择:

路线版本适用场景本文实测结论
A. 发行版仓库 apt install knot3.1.6(旧)只求快速、版本无要求可用,但 3.1.6 与官方 3.6.x 行为有代差
B. CZ.NIC 官方仓库(推荐主线)3.6.1(与上游同步)生产部署、需要新特性全文主线,实测通过
C. 源码编译任意版本/自定义模块需要 dnstap/geoip 等未编译模块见方案 C(官方 tarball 下载校验已实测,编译步骤为官方标准流程)

判断依据(2026-10-20 实查):官方下载页当前稳定分支为 3.6(3.6.1,2026-10-09 发布),上一稳定分支 3.5(EOL 2027 年 Q3);jammy/universe 的 3.1.6 属于上一代大版本,KASP、QUIC、XDP 等能力不可用。

四、安装方案 A:发行版仓库(3.1.6,对照用)

sudo apt install -y knot

实测回显(截取关键段):

The following NEW packages will be installed:
  libdnssec8 libknot12 liburcu8 libzscanner4 knot
0 upgraded, 5 newly installed, 0 to remove and 8 not upgraded.
Setting up knot (3.1.6-1ubuntu1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/knot.service → /lib/systemd/system/knot.service.

验证版本与服务状态:

knotd -V
systemctl is-enabled knot; systemctl is-active knot

实测回显:

knotd (Knot DNS) version 3.1.6
enabled
active

注意两点(3.1.6 装完即有的真实状态):

  1. 服务默认 enabled + active,随安装自启;
  2. 默认样例配置 /etc/knot/knot.conf 的 listen 行是注释状态,此时 knotd 正常运行但不监听任何 DNS 端口,日志出现:
warning: no network interface configured

体验完方案 A 后清理(purge 连同依赖一并删除,端口与文件还原):

sudo apt purge -y knot libknot12 libdnssec8 libzscanner4 liburcu8
ss -ltn | grep ':53 '   # 核验:knot 相关监听消失

实测回显(截取):

Removing knot (3.1.6-1ubuntu1) ...
Removing libknot12:amd64 (3.1.6-1ubuntu1) ...
Removing libdnssec8:amd64 (3.1.6-1ubuntu1) ...
Removing libzscanner4:amd64 (3.1.6-1ubuntu1) ...
Removing liburcu8:amd64 (0.13.1-1) ...

五、安装方案 B:CZ.NIC 官方仓库(3.6.1 主线)

5.1 接入仓库(四步)

# 1) 下载 CZ.NIC Labs Packaging GPG key(指纹 9C71 D59C D4CE 8BD2 966A 7A3E AB6A 3031 2401 9B64)
sudo wget -O /usr/share/keyrings/cznic-labs-pkg.gpg https://pkg.labs.nic.cz/gpg
# 2) 写入仓库源(jammy 对应 Ubuntu 22.04)
echo "deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/knot-dns jammy main" | sudo tee /etc/apt/sources.list.d/cznic-labs-knot-dns.list
# 3) 刷新索引
sudo apt update
# 4) 确认候选版本已是官方仓库版
apt-cache policy knot

实测回显(第 3 步,截取本仓库相关行):

Get:7 https://pkg.labs.nic.cz/knot-dns jammy InRelease [5,077 B]
Get:8 https://pkg.labs.nic.cz/knot-dns jammy/main amd64 Packages [3,796 B]

实测回显(apt-cache policy 第 4 步,完整):

knot:
  Installed: (none)
  Candidate: 3.6.1-cznic.1~jammy
  Version table:
 *** 3.6.1-cznic.1~jammy 500
        500 https://pkg.labs.nic.cz/knot-dns jammy/main amd64 Packages
     3.6.0-cznic.1~jammy 500
        500 https://pkg.labs.nic.cz/knot-dns jammy/main amd64 Packages
     3.5.9-cznic.1~jammy 500
        500 https://pkg.labs.nic.cz/knot-dns jammy/main amd64 Packages
     3.1.6-1ubuntu1 500
        500 http://cn.archive.ubuntu.com/ubuntu jammy/universe amd64 Packages

5.2 安装

sudo apt install -y knot knot-dnsutils

实测回显(apt 输出为中文 locale,关键段):

下列【新】软件包将被安装:
  knot knot-dnsutils knot-keymgr libknot17 libzscanner5
升级了 0 个软件包,新安装了 5 个软件包,要卸载 0 个软件包,有 205 个软件包未被升级。
正在解压 knot (3.6.1-cznic.1~jammy) ...
正在设置 libknot17:amd64 (3.6.1-cznic.1~jammy) ...
正在设置 libzscanner5:amd64 (3.6.1-cznic.1~jammy) ...
正在设置 knot (3.6.1-cznic.1~jammy) ...
正在设置 knot-dnsutils (3.6.1-cznic.1~jammy) ...
正在设置 knot-keymgr (3.6.1-cznic.1~jammy) ...
正在处理用于 man-db (2.10.2-1) 的触发器 ...

💡 技术拓展:knot(服务端:knotd/knotc/kxdpgun/kjournalprint/kcatalogprint/knsec3hash/kzonesign)、knot-dnsutils(客户端:kdig/knsupdate)、knot-keymgr(DNSSEC 密钥管理)三个包按角色拆分。只装 knot 不带 knot-dnsutils 的话,kdig 等客户端验证工具缺失。

5.3 装后验证

knotd -V
systemctl is-enabled knot; systemctl is-active knot
cat /etc/knot/knot.conf

实测回显:

knotd, Knot DNS 3.6.1
enabled
active

/etc/knot/knot.conf(CZ.NIC 包自带样例原文,注意 automatic-acl: on 在 server 节内、listen 与 remote/zone 示例均处于注释态):

# This is a sample of a minimal configuration file for Knot DNS.
# See knot.conf(5) or refer to the server documentation.

server:
    rundir: "/run/knot"
    user: knot:knot
    automatic-acl: on
#    listen: [ 127.0.0.1@53, ::1@53 ]

log:
  - target: syslog
    any: info

database:
    storage: "/var/lib/knot"

remote:
#  - id: secondary
#    address: 192.168.1.1@53
#
#  - id: primary
#    address: 192.168.2.1@53

template:
  - id: default
    storage: "/var/lib/knot"
    file: "%s.zone"

zone:
#    # Primary zone
#  - domain: example.com
#    notify: secondary

#    # Secondary zone
#  - domain: example.net
#    master: primary

服务资源占用(装完默认样例状态,systemd 视角):

● knot.service - Knot DNS server
     Loaded: loaded (/lib/systemd/system/knot.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2026-10-20 17:12:23 CST; 3s ago
       Docs: man:knotd(8)
             man:knot.conf(5)
             man:knotc(8)
    Process: 1419424 ExecStartPre=/usr/sbin/knotc conf-check (code=exited, status=0/SUCCESS)
   Main PID: 1419425 (knotd)
      Tasks: 37 (limit: 38359)
     Memory: 3.1M

六、安装方案 C:源码编译

适用:需要该 deb 包未编译的模块(实测本包 mod-dnstap/mod-geoip 不在编译集内),或要在非 Ubuntu 22.04 环境部署。

官方 3.6.1 源码包(来自官方下载页,2026-10-20 实查):

下载与完整性校验(实测通过):

wget https://secure.nic.cz/files/knot-dns/knot-3.6.1.tar.xz
wget https://secure.nic.cz/files/knot-dns/knot-3.6.1.tar.xz.sha256
sha256sum -c knot-3.6.1.tar.xz.sha256

实测回显:

knot-3.6.1.tar.xz: OK

编译遵循官方标准流程(./autogen.sh && ./configure && make && sudo make install,依赖工具链 autoconf/libtool/pkg-config、库 gnutls28/lmdb/liburcu/libedit;configure 阶段可 --enable-dnstap --enable-geoip 补齐模块)。该编译步骤为官方仓库 INSTALL 文档的标准流程,未在本文环境完整跑通回显,依赖细节以源码包内 INSTALL 文件为准;如无定制需求,优先使用方案 B。

七、方案对比与选择建议

对比项方案 A(distro)方案 B(CZ.NIC 官方仓库)方案 C(源码)
版本3.1.6(落后两个大版本)3.6.1 同步上游任意
维护随 Ubuntu 安全更新随上游持续更新自负
额外接入成本无加 1 个 key + 1 个源工具链 + 依赖全自备
DNSSEC 自动化有(KASP 早期实现)完整(含 3.x 全部改进)取决于编译开关
QUIC/XDP 新能力无有可选开关
适用临时实验生产默认选择定制模块/特殊平台

建议:生产环境用方案 B;方案 A 仅适合快速体验与本文的版本对照;方案 C 仅在有 dnstap/geoip/自定义编译需求时启用。

八、配置说明与首次启动闭环

8.1 实验配置(多 DNS 服务共存的监听策略)

覆盖 /etc/knot/knot.conf(53 端口冲突环境,绑定专用回环地址;干净机器可写 listen: [ 0.0.0.0@53, ::@53 ]):

server:
    rundir: "/run/knot"
    user: knot:knot
    listen: [ 127.0.0.9@53, ::1@53 ]

log:
  - target: syslog
    any: info

database:
    storage: "/var/lib/knot"

template:
  - id: default
    storage: "/var/lib/knot"
    file: "%s.zone"

zone:
  - domain: lab.example

zone 文件 /var/lib/knot/lab.example.zone:

$ORIGIN lab.example.
$TTL 3600
@       IN SOA ns1.lab.example. admin.lab.example. (
                2026102001 ; serial
                86400      ; refresh
                7200       ; retry
                3600000    ; expire
                3600 )     ; minimum
@       IN NS   ns1.lab.example.
ns1     IN A    127.0.0.1
www     IN A    192.168.1.100
api     IN A    192.168.1.101
@       IN MX   10 mail.lab.example.
mail    IN A    192.168.1.110
txt     IN TXT  "knot dns lab"

8.2 校验与生效(先校验、再重启、后验证)

sudo chown knot:knot /var/lib/knot/lab.example.zone
sudo knotc conf-check          # 配置语法校验,先于一切生效动作
sudo systemctl restart knot    # listen 变更必须 restart(reload 不重建监听,见 FAQ-4)

conf-check 实测回显:

Configuration is valid

监听核验(TCP 与 UDP 分开看):

ss -ltn | grep '127.0.0.9:53'
ss -lnup | grep '127.0.0.9:53' | head -3

实测回显:

LISTEN 0      10              127.0.0.9:53         0.0.0.0:*
UNCONN 0      0            127.0.0.9:53         0.0.0.0:*    users:(("knotd",pid=1425448,fd=17))
UNCONN 0      0            127.0.0.9:53         0.0.0.0:*    users:(("knotd",pid=1425448,fd=16))
UNCONN 0      0            127.0.0.9:53         0.0.0.0:*    users:(("knotd",pid=1425448,fd=15))

UDP 套接字按 worker 数量成组打开(12 核默认 12 个 UDP fd),ss 输出会看到多行同地址 UDP,属正常。

服务运行态确认:

systemctl status knot --no-pager | sed -n '1,11p'
knotc status workers

实测回显:

● knot.service - Knot DNS server
     Loaded: loaded (/lib/systemd/system/knot.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2026-10-20 17:16:02 CST; 1s ago
       Docs: man:knotd(8)
             man:knot.conf(5)
             man:knotc(8)
    Process: 1424241 ExecStartPre=/usr/sbin/knotc conf-check (code=exited, status=0/SUCCESS)
   Main PID: 1424242 (knotd)
      Tasks: 39 (limit: 38359)
     Memory: 4.0M
        CPU: 16ms
UDP workers: 12, TCP workers: 12, XDP workers: 0, background workers: 10 (running: 0, pending: 0)

8.3 解析验证

kdig @127.0.0.9 lab.example SOA +short
kdig @::1 lab.example NS +short
kdig @127.0.0.9 www.lab.example A

实测回显:

ns1.lab.example. admin.lab.example. 2026102001 86400 7200 3600000 3600
ns1.lab.example.
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 9438
;; Flags: qr aa rd; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1

;; EDNS PSEUDOSECTION:
;; Version: 0; flags: ; UDP size: 1232 B; ext-rcode: NOERROR

;; QUESTION SECTION:
;; www.lab.example.             IN      A

;; ANSWER SECTION:
www.lab.example.        3600    IN      A       192.168.1.100

;; Received 60 B
;; Time 2026-10-20 17:16:03 CST
;; From 127.0.0.9@53(UDP) in 0.2 ms

至此安装-配置-运行-解析四步闭环完成。DDNS 动态更新、DNSSEC 自动签名、AXFR 主从传输等能力级验证见《Knot DNS 3.6.1 常用 CLI 命令与工具详解》。

九、升级、降级与多版本管理

9.1 查看可用版本

apt-cache policy knot

输出见 5.1 节(官方仓库内 3.5.4/3.5.9/3.6.0/3.6.1 与 distro 3.1.6 并列,版本号后缀 cznic.1~jammy 区分来源)。

9.2 降级实测(3.6.1 → 3.5.9)

降级必须显式指定连带库版本,否则 apt 因库依赖冲突拒绝执行。先查目标版本依赖:

apt-cache show knot=3.5.9-cznic.1~jammy | grep -E '^Depends'

实测回显:

Depends: libbrotli1, libdnssec10 (>= 3.5.9), libfstrm0, libgnutls30 (>= 3.7.3), libknot16 (>= 3.5.9), liblmdb0, libmaxminddb0, libnghttp2-14, libprotobuf-c1, liburcu8, libzscanner5 (>= 3.5.9), netbase, adduser, lsb-base

连库一起降级:

sudo apt install -y --allow-downgrades \
  knot=3.5.9-cznic.1~jammy knot-dnsutils=3.5.9-cznic.1~jammy knot-keymgr=3.5.9-cznic.1~jammy \
  libzscanner5=3.5.9-cznic.1~jammy libknot16=3.5.9-cznic.1~jammy libdnssec10=3.5.9-cznic.1~jammy
knotd -V
systemctl is-active knot
kdig @127.0.0.9 lab.example SOA +short

实测回显(关键行,apt 为中文 locale):

正在设置 libknot16:amd64 (3.5.9-cznic.1~jammy) ...
正在设置 knot (3.5.9-cznic.1~jammy) ...
正在处理用于 man-db (2.10.2-1) 的触发器 ...
knotd, Knot DNS 3.5.9
active
ns1.lab.example. admin.lab.example. 2026102001 86400 7200 3600000 3600

降级后 zone 数据与 serial 完好(journal 兼容),服务无中断地继续权威应答。

9.3 升级回 3.6.1

sudo apt install -y knot knot-dnsutils knot-keymgr
knotd -V
systemctl is-active knot
kdig @127.0.0.9 lab.example SOA +short

实测回显:

knotd, Knot DNS 3.6.1
active
ns1.lab.example. admin.lab.example. 2026102001 86400 7200 3600000 3600

💡 技术拓展:降级前先 knotc zone-backup 备份(含 DNSSEC 密钥库),跨大版本降级前更应做;本实验因同主版本线内小版本互换(3.6.1↔3.5.9)且 zone 未开签名,未做备份。--allow-downgrades 是降级的必要参数;连带库(libknot/libzscanner)的 SONAME 会随大版本变化,必须逐个指定版本号。另注意 3.6 起库布局变化:3.5.x 还需要独立 libdnssec 动态库(降级 3.5.9 必须连 libdnssec10 一起指定),而 3.6.x 的 DNSSEC 功能已并入 libknot(实测 3.6.1 的 knotd 与 keymgr 均只链接 libknot.so.17,系统内无 libdnssec 动态库)。

十、常见问题(FAQ)

FAQ-1:启动报 cannot bind address ... (address already in use)

现象(53 被其他服务占用时 start 的真实报错,journalctl 原文):

knotd[1398358]: error: cannot bind address 127.0.0.1@53 UDP (address already in use)
knotd[1398358]: critical: failed to configure server
systemd[1]: knot.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: knot.service: Failed with result 'exit-code'.
systemd[1]: Failed to start Knot DNS server.

处置:ss -ltnup | grep ':53 ' 找出占用者(本机是 systemd-resolved 的 127.0.0.53 与其他 DNS 实例),然后二选一:① Knot 的 listen 改绑具体空闲地址(本文做法,多服务共存最稳);② 关闭占用方(如禁用 DNSStubListener)后再绑全局地址。

FAQ-2:装完服务是 active 但 53 端口没监听

/etc/knot/knot.conf 默认样例的 listen 行是注释态,knotd 起来后只开控制套接字不开 DNS 端口,日志报 warning: no network interface configured。取消注释并配好监听地址、systemctl restart knot 即可(见 8.2 节)。

FAQ-3:改了 knot.conf 但重启后不生效——confdb 机制

Knot 启动读取的是二进制配置数据库 /var/lib/knot/confdb(LMDB),文本 knot.conf 只在 confdb 缺失时首次导入。改完文本文件后用 knotc reload 生效(热加载多数参数);若配置库与文本文件彻底脱节,删除 confdb 后重启让 knotd 重新导入:

sudo systemctl stop knot
sudo rm -rf /var/lib/knot/confdb
sudo systemctl start knot

重要教训(实测踩坑):绝不要在运行中的系统上以 root 跑 knotc conf-init——它会重建 confdb 且属主变为 root,随后服务因权限启动失败,真实报错链:

knotc[1397243]: error: failed to open configuration database '/var/lib/knot/confdb' (operation not permitted)
systemd[1]: knot.service: Failed with result 'exit-code'.
systemd[1]: Failed to start Knot DNS server.

修复:sudo chown -R knot:knot /var/lib/knot/confdb,或直接删掉 confdb 让 knotd 重建(推荐后者,文本配置才是唯一事实源)。

FAQ-4:knotc reload 不会重建监听套接字

实测:向 listen 追加 127.0.0.15@53 后执行 knotc reload,ss 核验新地址没有绑定(reload 生效的是 zone/ACL/模块等参数)。listen 变更必须 systemctl restart knot。这是 3.6.1 的实际行为,生产变更监听时按「改配置 → restart → ss 核验」执行。

FAQ-5:zone 文件写错了,knotc zone-reload 还回 OK

zone-reload 默认异步下发指令,加载失败只体现在服务端日志(控制通道回 OK):

knotc zone-reload lab.example
# 回显: OK
journalctl -u knot --no-pager --output=cat | tail -4
error: [lab.example.] zone loader, error in zone, file '/var/lib/knot/lab.example.zone', line 3 (invalid IPv4 address)
error: [lab.example.] zone loader, failed to load, file '/var/lib/knot/lab.example.zone', 1 errors
error: [lab.example.] failed to parse zone file '/var/lib/knot/lab.example.zone' (failed)
error: [lab.example.] zone event 'load' failed (failed)

需要同步拿到加载结果时用阻塞模式:knotc -b zone-reload lab.example(坏文件时直接回 error: (failed) [lab.example] 且退出码 1)。

十一、卸载与清理

# 1) 停服务并卸载(含 DNSSEC 密钥库、journal、confdb)
sudo systemctl stop knot
sudo apt purge -y knot knot-dnsutils knot-keymgr libknot17 libzscanner5 liburcu8
# 2) 删除残留数据目录(见下方回显:/var/lib/knot 非空时 purge 不会删)
sudo rm -rf /var/lib/knot /run/knot
# 3) 若不再使用官方仓库,删除仓库源与 key
sudo rm -f /etc/apt/sources.list.d/cznic-labs-knot-dns.list /usr/share/keyrings/cznic-labs-pkg.gpg
sudo apt update
# 4) 核验还原
ss -ltn | grep ':53 '
systemctl is-active knot

实测回显(purge 阶段,中文 locale 原文):

下列软件包将被【卸载】:
  knot* knot-dnsutils* knot-keymgr* libknot17* liburcu8* libzscanner5*
正在删除 knot (3.6.1-cznic.1~jammy) ...
正在清除 knot (3.6.1-cznic.1~jammy) 的配置文件 ...
dpkg: 警告: 卸载 knot 时,目录 /var/lib/knot 非空,因而不会删除该目录

注意:purge 删除 /etc/knot,但 /var/lib/knot 里属于运行数据的 zone 文件/journal/密钥库不会被自动删除(如上方警告),须手动 rm -rf /var/lib/knot /run/knot。另注意 liburcu8 可能被系统其他组件依赖,apt 拒绝时跳过该包名即可。

十二、参考链接