Ubuntu 22.04 安装 DNSControl 5.7 指南
Ubuntu 22.04 从零安装 DNSControl v5.7.0(tar.gz 二进制与官方 deb 双方案实测),含 sha256 校验、BIND provider 的 check/preview/push/dig 全闭环验证、升级卸载与段错误等排障实录。
Ubuntu 22.04 安装 DNSControl 5.7 指南
目标:在 Ubuntu 22.04 服务器上从零安装 DNSControl v5.7.0(官方 tar.gz 二进制与 deb 包两种方案),完成首次配置并用 BIND9 本地 zone 文件跑通
check → preview → push → dig 验证全闭环。全部命令与回显来自 2026-10-25 的真实环境实测。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(Jammy),x86_64,GLIBC 2.35
- 软件版本:DNSControl v5.7.0(2026-10-21 发布的最新稳定版)
- 验证用 DNS 服务器:BIND 9.18.39-0ubuntu0.22.04.7(Ubuntu 官方仓库,
named/dig均来自该版本) - 关键路径:配置目录
/etc/dnscontrol/;zone 文件目录/srv/zones/primary/;二进制/usr/local/bin/dnscontrol(方案 A)或/usr/bin/dnscontrol(方案 B) - 演示域名:
example.io(内网演示,解析地址 192.168.1.71/192.168.1.72、2001:db8::71)
⚠️ 网络说明:实测当日 GitHub Releases 直连下载两次中断(
HTTP/2 PROTOCOL_ERROR、SSL_read: Connection reset by peer),改用代理渠道后完整下载成功。下载后务必做 sha256 校验——截断的包能解压出残缺二进制,直接运行会段错误(排障实录见九、常见问题)。
二、前置条件
DNSControl 是 Go 编写的单文件静态二进制,无运行时依赖(不依赖 JDK/Python/数据库),root 或 sudo 权限即可安装。本机环境确认:
uname -m
. /etc/os-release; echo "$PRETTY_NAME"
ldd --version | head -1
实测回显:
x86_64
Ubuntu 22.04.5 LTS
ldd (Ubuntu GLIBC 2.35-0ubuntu3.15) 2.35
为了跑通端到端验证(第六节),需要一台 BIND9 作为权威 DNS。Ubuntu 仓库直接安装:
apt-get update
apt-get install -y bind9 dnsutils
named -v
dig -v | head -1
实测回显(已装环境为幂等提示,新装环境为正常安装流水):
bind9 is already the newest version (1:9.18.39-0ubuntu0.22.04.7).
dnsutils is already the newest version (1:9.18.39-0ubuntu0.22.04.7).
BIND 9.18.39-0ubuntu0.22.04.7-Ubuntu (Extended Support Version) <id:>
DiG 9.18.39-0ubuntu0.22.04.7-Ubuntu
三、版本选型说明
v5.7.0 官方 Release 为各平台提供的发布件(sha256 取自官方 checksums.txt,2026-10-25 检索):
| 发布件 | 适用平台 | 本机是否适用 |
|---|---|---|
dnscontrol_5.7.0_linux_amd64.tar.gz | Linux x86_64(含 LICENSE/README/二进制) | 是(方案 A) |
dnscontrol-5.7.0.amd64.deb | Debian/Ubuntu x86_64 | 是(方案 B) |
dnscontrol_5.7.0_linux_arm64.tar.gz | Linux ARM64 | 否 |
dnscontrol-5.7.0.arm64.deb / *.arm64.rpm / *.x86_64.rpm | ARM64 deb / RPM 系 | 否 |
dnscontrol_5.7.0_darwin_all.tar.gz | macOS(通用) | 否 |
dnscontrol_5.7.0_windows_amd64.zip / windows_arm64.zip | Windows | 否 |
dnscontrol_5.7.0_freebsd_*.tar.gz | FreeBSD | 否 |
选型要点:Ubuntu 22.04 x86_64 可选 tar.gz 二进制(装到 /usr/local/bin,卸载干净、便于多版本并存)或 deb 包(装到 /usr/bin,纳入 dpkg 管理)。两者二进制完全相同,按团队包管理规范二选一即可。
四、方案 A:官方 tar.gz 二进制安装(推荐)
4.1 方案说明
从 GitHub Releases 下载官方 tar.gz,sha256 校验后解出单一二进制安装到 /usr/local/bin。优点:路径独立、升级/降级就是换文件、不污染 dpkg 数据库。
4.2 下载与校验
mkdir -p /opt/src && cd /opt/src
curl -fsSL -O https://github.com/DNSControl/dnscontrol/releases/download/v5.7.0/dnscontrol_5.7.0_linux_amd64.tar.gz
curl -fsSL -O https://github.com/DNSControl/dnscontrol/releases/download/v5.7.0/checksums.txt
grep linux_amd64 checksums.txt | sha256sum -c -
实测回显(重试后完整下载,校验通过):
dnscontrol_5.7.0_linux_amd64.tar.gz: OK
官方 checksums.txt 中本发布件的标准值(供核对):
c120b45a550c18c94ba2fddd09cbcddbe116e6040be12657afe7144670afc8a1 dnscontrol_5.7.0_linux_amd64.tar.gz
⚠️ 注意:直连 GitHub 不稳定时按「官方源 → 代理」降级重试,但任何渠道下载后都必须过 sha256 校验。实测第一次直连下载到 8.8MB 即断开(完整包 32,434,947 字节),残缺包解压出的二进制运行即段错误,详见九、常见问题。
4.3 解压与安装
tar -xzf dnscontrol_5.7.0_linux_amd64.tar.gz -C /opt/src
ls -l /opt/src
install -m 0755 /opt/src/dnscontrol /usr/local/bin/dnscontrol
实测回显:
-rw-r--r-- 1 1001 1001 1086 Oct 21 13:17 LICENSE
-rw-r--r-- 1 1001 1001 11181 Oct 21 13:19 README.md
-rw-r--r-- 1 root root 1088 Oct 25 15:09 checksums.txt
-rwxr-xr-x 1 1001 1001 135127200 Oct 21 13:26 dnscontrol
-rw-r--r-- 1 root root 32434947 Oct 25 13:50 dnscontrol_5.7.0_linux_amd64.tar.gz
压缩包内只有 LICENSE、README.md、dnscontrol 三个文件,install 将二进制以 0755 权限复制到 /usr/local/bin。
4.4 验证
ls -l /usr/local/bin/dnscontrol
/usr/local/bin/dnscontrol version
实测回显:
-rwxr-xr-x 1 root root 135127200 Oct 25 15:10 /usr/local/bin/dnscontrol
v5.7.0
输出版本号 v5.7.0 即安装成功。DNSControl 是无常驻进程的 CLI 工具,无需 systemd 托管;需要定时漂移检测的场景见七、配置说明的 cron 示例。
五、方案 B:官方 deb 包安装(dpkg 管理)
5.1 方案说明
v5.7.0 官方同时提供 dnscontrol-5.7.0.amd64.deb,适合要求「全部软件纳入 dpkg 台账」的服务器。deb 将二进制安装到 /usr/bin/dnscontrol。
5.2 下载与校验
cd /opt/src
curl -fsSL -O https://github.com/DNSControl/dnscontrol/releases/download/v5.7.0/dnscontrol-5.7.0.amd64.deb
sha256sum dnscontrol-5.7.0.amd64.deb
实测回显(与官方 checksums.txt 完全一致):
39c4aa8d994299d1ccac6d42f2c5fb64fb114f2346606040def55da36e2d3744 dnscontrol-5.7.0.amd64.deb
5.3 安装
dpkg -i dnscontrol-5.7.0.amd64.deb
实测回显:
Selecting previously unselected package dnscontrol.
(Reading database ... 5419 files and directories currently installed.)
Preparing to unpack dnscontrol-5.7.0.amd64.deb ...
Unpacking dnscontrol (5.7.0) ...
Setting up dnscontrol (5.7.0) ...
5.4 验证
dpkg -s dnscontrol | sed -n '1,10p'
dpkg -L dnscontrol
which -a dnscontrol
/usr/bin/dnscontrol version
实测回显:
Package: dnscontrol
Status: install ok installed
Priority: optional
Installed-Size: 131960
Maintainer: Tom Limoncelli <tal@whatexit.org>
Architecture: amd64
Version: 5.7.0
Description: DNSControl: Infrastructure as Code for DNS Zones
Homepage: https://docs.dnscontrol.org/
/usr
/usr/bin
/usr/bin/dnscontrol
/usr/local/bin/dnscontrol
/usr/bin/dnscontrol
/bin/dnscontrol
v5.7.0
which -a 的第一行 /usr/local/bin/dnscontrol 来自方案 A——两方案并存时 PATH 优先命中 /usr/local/bin。正式机请只保留一种安装方式,避免双副本版本漂移(见十、卸载与清理)。
5.5 方案对比与选择建议
| 维度 | 方案 A:tar.gz 二进制 | 方案 B:deb 包 |
|---|---|---|
| 安装路径 | /usr/local/bin/dnscontrol | /usr/bin/dnscontrol |
| 包管理 | 不纳入 dpkg | 纳入 dpkg(dpkg -s/-L/-r 可查) |
| 升级方式 | 换文件 | dpkg -i 新包 |
| 多版本并存 | 容易(改文件名即可) | 不便 |
| 适用 | 手工维护的工具机、多版本灰度 | 配置管理(Ansible/Salt)统一台账的服务器 |
两者二进制一致(均为 135127200 字节、v5.7.0),按团队规范任选其一。
六、首次配置与 0→1 验证(BIND provider 打通)
本节用 BIND provider 把 DNSControl 与本机 BIND9 打通:DNSControl 负责生成 zone 文件,BIND9 负责对外解析。这是零外部账号依赖的最小闭环,接通后再换成云厂商 provider 只是改 creds.json 的事。
6.1 配置目录与 creds.json
mkdir -p /etc/dnscontrol /srv/zones/primary
cd /etc/dnscontrol
cat > creds.json <<'EOF'
{
"bind": {
"TYPE": "BIND",
"directory": "/srv/zones/primary"
}
}
EOF
chmod 600 creds.json
ls -l /etc/dnscontrol
实测回显:
total 4
-rw------- 1 root root 78 Oct 25 15:10 creds.json
要点:creds.json 的顶层键 bind 是 provider 实例名(后面 dnsconfig.js 里按名引用);TYPE: "BIND" 指定 provider 类型;directory 是 zone 文件输出目录。BIND provider 无需密码,但云厂商凭证也写在这一个文件里,统一 chmod 600 收敛权限。
6.2 首个 dnsconfig.js
cat > /etc/dnscontrol/dnsconfig.js <<'EOF'
var REG_NONE = NewRegistrar("none");
var DSP_BIND = NewDnsProvider("bind", {
"default_soa": {
"master": "ns1.example.io.",
"mbox": "hostmaster.example.io.",
"refresh": 3600,
"retry": 600,
"expire": 604800,
"minttl": 300
}
});
D("example.io", REG_NONE, DnsProvider(DSP_BIND),
NAMESERVER("ns1.example.io."),
A("ns1", "192.168.1.71"),
A("@", "192.168.1.71"),
A("www", "192.168.1.72"),
AAAA("www", "2001:db8::71"),
CNAME("blog", "www.example.io."),
MX("@", 10, "mail.example.io."),
A("mail", "192.168.1.71"),
TXT("@", "v=spf1 ip4:192.168.1.71 -all"),
TXT("_dmarc", "v=DMARC1; p=none; rua=mailto:dmarc@example.io"),
SRV("_sip._tcp", 10, 60, 5060, "sip.example.io."),
CAA("@", "issue", "letsencrypt.org")
);
EOF
cd /etc/dnscontrol && dnscontrol check
实测回显:
No errors.
check 只做离线语法与合法性校验、不触碰 provider,输出 No errors. 即配置可进入下一步。DSL 各函数详解见本专栏配置参数篇,这里先把流程打通。
6.3 preview:先看差异
cd /etc/dnscontrol && dnscontrol preview
实测回显:
CONCURRENTLY checking for 1 zone(s)
Waiting for concurrent checking(s) to complete...DONE
******************** Domain: example.io
1 correction (bind)
#1: Ensuring zone "example.io" exists in "bind"
CONCURRENTLY gathering records of 1 zone(s)
Waiting for concurrent gathering(s) to complete...DONE
******************** Domain: example.io
INFO#1: Zone "example.io" does not yet exist at provider "bind". It will be created when you run `dnscontrol push`.
Done. 1 corrections.
首次运行提示 zone 不存在,1 个待执行变更(创建 zone),preview 不会落任何文件。
6.4 push:应用变更
cd /etc/dnscontrol && dnscontrol push
实测回显:
CONCURRENTLY checking for 1 zone(s)
Waiting for concurrent checking(s) to complete...DONE
******************** Domain: example.io
1 correction (bind)
#1: Ensuring zone "example.io" exists in "bind"
SUCCESS!
CONCURRENTLY gathering records of 1 zone(s)
Waiting for concurrent gathering(s) to complete...DONE
******************** Domain: example.io
13 corrections (bind)
#1: + CREATE example.io SOA ns1.example.io. hostmaster.example.io. X 3600 600 604800 300 ttl=300
+ CREATE example.io A 192.168.1.71 ttl=300
+ CREATE example.io TXT "v=spf1 ip4:192.168.1.71 -all" ttl=300
+ CREATE example.io CAA 0 issue "letsencrypt.org" ttl=300
+ CREATE _dmarc.example.io TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.io" ttl=300
+ CREATE _sip._tcp.example.io SRV 10 60 5060 sip.example.io. ttl=300
+ CREATE mail.example.io A 192.168.1.71 ttl=300
+ CREATE ns1.example.io A 192.168.1.71 ttl=300
+ CREATE www.example.io A 192.168.1.72 ttl=300
+ CREATE www.example.io AAAA 2001:db8::71 ttl=300
+ CREATE example.io NS ns1.example.io. ttl=300
+ CREATE example.io MX 10 mail.example.io. ttl=300
+ CREATE blog.example.io CNAME www.example.io. ttl=300
WRITING ZONEFILE: "/srv/zones/primary/example.io.zone" (serial 2026102500)
SUCCESS!
Done. 14 corrections.
push 把 13 条记录 + 1 次 zone 创建共 14 项变更写入 /srv/zones/primary/example.io.zone,SOA serial 自动按日期生成(2026102500)。生成的 zone 文件:
cat /srv/zones/primary/example.io.zone
实测回显:
$TTL 300
; generated with dnscontrol 2026-10-25T15:10:00Z
@ IN SOA ns1.example.io. hostmaster.example.io. 2026102500 3600 600 604800 300
IN NS ns1.example.io.
IN A 192.168.1.71
IN MX 10 mail.example.io.
IN TXT "v=spf1 ip4:192.168.1.71 -all"
IN CAA 0 issue "letsencrypt.org"
_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.io"
_sip._tcp IN SRV 10 60 5060 sip.example.io.
blog IN CNAME www.example.io.
mail IN A 192.168.1.71
ns1 IN A 192.168.1.71
www IN A 192.168.1.72
IN AAAA 2001:db8::71
6.5 BIND9 加载并解析验证
把生成的 zone 挂进 BIND9(真实服务器上用 systemd 服务的 BIND9 同理,改的是同一份 named.conf.local):
cat >> /etc/bind/named.conf.local <<'EOF'
zone "example.io" {
type master;
file "/srv/zones/primary/example.io.zone";
allow-update { none; };
};
EOF
named-checkconf
rndc reload
实测回显:
named-checkconf rc=0
server reload successful
逐条 dig 验证解析结果:
dig @127.0.0.1 +short SOA example.io
dig @127.0.0.1 +short NS example.io
dig @127.0.0.1 +short A example.io
dig @127.0.0.1 +short A www.example.io
dig @127.0.0.1 +short AAAA www.example.io
dig @127.0.0.1 +short CNAME blog.example.io
dig @127.0.0.1 +short MX example.io
dig @127.0.0.1 +short TXT example.io
dig @127.0.0.1 +short SRV _sip._tcp.example.io
dig @127.0.0.1 +short CAA example.io
实测回显(与上方 dig 命令一一对应):
ns1.example.io. hostmaster.example.io. 2026102500 3600 600 604800 300
ns1.example.io.
192.168.1.71
192.168.1.72
2001:db8::71
www.example.io.
10 mail.example.io.
"v=spf1 ip4:192.168.1.71 -all"
10 60 5060 sip.example.io.
0 issue "letsencrypt.org"
十条记录全部与 dnsconfig.js 声明一致,0→1 闭环打通。
6.6 幂等性验证
配置未变时再跑 preview,应报 0 变更(--full 额外打印各 provider 汇总与统计):
cd /etc/dnscontrol && dnscontrol preview --full
实测回显(节选首尾):
CONCURRENTLY checking for 1 zone(s)
Waiting for concurrent checking(s) to complete...DONE
...
******************** Domain: example.io
----- DNS Provider: bind...
0 corrections (bind)
----- Registrar: none...
0 corrections (none)
Inaccurate statistics: {"memory_in_use":17832200,"memory_in_use_str":"18 MB","num_records":12,"num_zones":1,"rc_size":200,"benchmark1":1486016,"benchmark1str":"1.4 MiB bytes"}
Done. 0 corrections.
0 corrections 说明工具幂等:期望状态与线上状态一致时不做任何修改。统计行显示本次管理 1 个 zone、12 条记录、进程内存约 18 MB。
七、配置说明
/etc/dnscontrol/dnsconfig.js:主配置(声明式 DSL),建议纳入 Git 管理;路径可用--config覆盖。/etc/dnscontrol/creds.json:provider 凭证与参数,chmod 600;路径可用--creds覆盖,也可写成!命令让外部程序动态输出 JSON。/srv/zones/primary/:BIND provider 的 zone 文件输出目录(在creds.json的directory里指定),BIND9 的named.conf.local逐个 zone 引用其中的文件;push后需rndc reload让 BIND9 载入新文件。- 定时漂移检测(可选):DNSControl 无常驻进程,用 cron 每天比对一次线上是否被人为改动:
cat > /etc/cron.d/dnscontrol-drift <<'EOF'
17 3 * * * root cd /etc/dnscontrol && /usr/local/bin/dnscontrol preview --expect-no-changes || echo "DNS drift detected" | mail -s "dnscontrol drift" root
EOF
--expect-no-changes 在存在未声明变更时返回非零,配合邮件即可告警。
八、升级、降级与多版本管理
- 方案 A(tar.gz):下载新版本 tar.gz → 校验 →
install覆盖/usr/local/bin/dnscontrol;降级同理覆盖回旧版。多版本并存可把二进制命名成dnscontrol-5.7.0、dnscontrol-5.6.0,用时显式调用全路径。 - 方案 B(deb):
dpkg -i新版本即升级(显示Unpacking dnscontrol (新版) over (旧版));降级先dpkg -r dnscontrol再装旧包。 - 升级前阅读对应版本 Release Notes 的 Deprecation warnings 段(如官方预告
REV()将在后续版本从 RFC2317 切到 RFC4183,属破坏性变更)。 - 验证升级结果统一用
dnscontrol version,应输出目标版本号:
v5.7.0
九、常见问题
9.1 运行二进制报 Segmentation fault
现象:tar -xzf 解出的 dnscontrol 执行 version 直接段错误。
定位:实测中第一次直连 GitHub 下载被中断(curl 报 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR / SSL_read: Connection reset by peer),tar.gz 只有 8.8MB(完整应为 32,434,947 字节),tar 解出残缺的 32MB 二进制(完整应为 135127200 字节),运行即段错误。
解决:删除残缺文件,换可用渠道重新下载,并用官方 checksums.txt 校验通过后再解压安装。校验不通过的包一律不要用。
9.2 push 时报 could not create zonefile: no such file or directory
现象:WRITING ZONEFILE 一行后报 FAILURE! could not create zonefile: open /srv/zones/notexist/example.io.zone: no such file or directory,末尾 completed with errors。
定位:creds.json 里 directory 指向的目录不存在。
解决:mkdir -p 建好目录再 push;注意 zone 文件本身 DNSControl 会自动创建,但父目录不会。另外此类失败时 push 退出码仍为 0(变更列表照跑、最后报 completed with errors),自动化场景要同时检查输出文本。
9.3 push 成功但 dig 还是旧记录
现象:push 显示 WRITING ZONEFILE ... (serial 2026102502)、SUCCESS!,但 dig 返回修改前的地址。
定位:DNSControl 只负责写 zone 文件,BIND9 不会自动感知文件变化。
解决:每次 push 后执行 rndc reload 再验证。实测对照:未 reload 时 www.example.com 解析为旧值 192.168.1.32,rndc reload 后即新值 192.168.1.33。
9.4 creds.json 里 TYPE 写错导致初始化失败
现象:failed to initialize DNS provider "bind": if cloudflare apitoken is not set, apikey and apiuser must be provided。
定位:实例名 bind 与 TYPE 必须配套——上面这个报错是把 TYPE 误写成 CLOUDFLAREAPI(实例名仍叫 bind),DNSControl 按 TYPE 去初始化 Cloudflare 插件,自然缺凭证。
解决:TYPE 写目标 provider 的官方类型名(自建 BIND 写 "BIND"),实例名可自由起名但建议与类型可对应。
9.5 creds.json 文件缺失
现象:INFO: Config file "/etc/dnscontrol/nope.json" does not exist. Skipping.,随后 provider 初始化失败退出码 1。
解决:确认工作目录下存在 creds.json,或用 --creds=/etc/dnscontrol/creds.json 显式指定。
十、卸载与清理
方案 B(deb)卸载实测:
dpkg -r dnscontrol
实测回显:
(Reading database ... 5420 files and directories currently installed.)
Removing dnscontrol (5.7.0) ...
方案 A(tar.gz)卸载直接删二进制:
rm -f /usr/local/bin/dnscontrol
清理配置与生成的 zone 文件(按需,BIND9 中对应 zone 段先摘除):
rm -rf /etc/dnscontrol
rm -rf /srv/zones/primary
rm -f /etc/cron.d/dnscontrol-drift
十一、参考链接
- 官方仓库与发布件:
https://github.com/DNSControl/dnscontrol/releases/tag/v5.7.0 - 官方文档站(Getting Started):
https://docs.dnscontrol.org/ - 《DNSControl 5.7 介绍与选型指南》