本页内容
- 先决条件
- 安装 Unbound
- 配置 Unbound DNS 服务器 基本配置 启用 DNS 缓存 Unbound 隐私与安全 定义私有网络与访问控制列表(ACL) 设置本地域名 Unbound 性能调优 将 Unbound 配置为支持 DNS-over-TLS(DoT)的 DNS 解析器
- 配置 UFW 防火墙
- 通过 Rsyslog 和 Logrotate 记录 Unbound 日志
- 在 Linux 客户端上设置 DNS 解析器 适用于使用 NetworkManager 和 Systemd-resolved 的 Ubuntu 客户端 适用于 Debian 客户端
- 测试 Unbound DNS 服务器
- 结论
- 基本配置
- 启用 DNS 缓存
- Unbound 隐私与安全
- 定义私有网络与访问控制列表(ACL)
- 设置本地域名
- Unbound 性能调优
- 将 Unbound 配置为支持 DNS-over-TLS(DoT)的 DNS 解析器
- 适用于使用 NetworkManager 和 Systemd-resolved 的 Ubuntu 客户端
- 适用于 Debian 客户端
Unbound 是免费开源的 DNS 服务器软件,可用作验证、递归和缓存 DNS 解析器。它是一个功能丰富的 DNS 服务器,支持 DNS-over-TLS(DoT)、DNS-over-HTTPS(DoH)、查询名称最小化(Query Name Minimisation)、DNSSEC 验证缓存的激进使用(Aggressive Use of DNSSEC-Validated Cache),以及权威区域(authority zones)支持。Unbound 专注于 DNS 的隐私与安全,同时不牺牲速度和性能。
Unbound 主要由 NLnet Labs 开发,并在 BSD 许可下发布,它支持基于开放标准的 DNS 服务器现代特性。Unbound 已经过严格审计,可以运行在 Linux、BSD 和 macOS 上。Unbound 可用于大多数这些操作系统,并可以通过系统包管理器安装。
在本指南中,你将学习如何在 Debian 11 和 Debian 12 服务器上使用 Unbound 搭建私有 DNS 服务器。你将把 Unbound 配置为具有某些特性的本地 DNS 服务器,例如充当权威 DNS 服务器、启用 DNS 缓存、设置本地 IP 地址和访问控制列表(ACL)、配置本地域名,然后将 Unbound 配置为启用了 DNS-over-TLS(DoT)的 DNS 解析器。
此外,你还将通过 Rsyslog 和 Logrotate 为 Unbound 服务配置日志记录。
先决条件
要完成本指南,你必须满足以下要求。
- 运行 Debian 11 或 Debian 12 服务器的系统。
- 具有 sudo/root 管理员权限的用户账户。
就这些了。你现在可以开始将 Unbound 作为本地 DNS 服务器进行安装。
安装 Unbound
默认情况下,Unbound 软件包在 Debian 仓库中可用。你可以通过 APT 安装它。在第一步中,你将安装 Unbound 软件包,它会将 'dns-root-data' 包含到你的 Debian 服务器中。
在开始之前,通过下面的 apt 命令更新并刷新你的 Debian 软件包索引。
sudo apt update
现在运行下面的 apt 命令来检查 Debian 仓库中可用的 'unbound' 软件包。
sudo apt info unbound
下面的输出确认 Unbound 软件包默认在 Debian 服务器仓库中可用,当前版本为 1.13。

现在运行下面的 apt 命令将 unbound 安装到你的 Debian 系统。出现提示时,输入 y 确认并按 ENTER 继续。
sudo apt install unbound
输出:

Unbound 安装完成后,运行下面的 systemctl 命令来验证 Unbound 服务,并确保该服务已启用且正在运行。
sudo systemctl is-enabled unbound
sudo systemctl status unbound
Unbound 服务已启用,并将在系统启动时自动启动。Unbound 服务的状态为正在运行。

补充说明,如果你在 Debian 服务器上禁用了 IPv6,Unbound 将无法启动。要解决此问题,你可以在 Unbound 配置文件 '/etc/unbound/unbound.conf' 的 'server' 部分添加参数 'do-ip6: no'。
Unbound 安装完成后,接下来你将开始在你的系统上配置 Unbound。
配置 Unbound DNS 服务器
Unbound 的默认配置位于 '/etc/unbound/unbound.conf'。在这一步中,你将通过你喜欢的编辑器修改 Unbound 的主配置文件 '/etc/unbound.conf'。
现在你将了解 Unbound DNS 服务器的基本配置。
基本配置
使用你喜欢的编辑器打开 Unbound 的默认配置文件 '/etc/unbound/unbound.conf'。本例使用 nano 来编辑配置文件 '/etc/unbound/unbound.conf'。
sudo nano /etc/unbound/unbound.conf
将以下行添加到文件中。你可以在 'server' 部分设置 Unbound 的基本配置。在本例中,你将在本地 IP 地址 '192.168.5.20' 上使用默认端口 53 运行 Unbound。此外,你将配置向 Syslog 消息记录日志,并禁用 IPv6。最后,你将配置 Unbound 通过 'root-hints' 文件从根 DNS 服务器递归查询任何主机名。
#Adding DNS-Over-TLS support server: use-syslog: yes username: "unbound" directory: "/etc/unbound" tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt do-ip6: no interface: 192.168.5.20 port: 53 prefetch: yes root-hints: /usr/share/dns/root.hints harden-dnssec-stripped: yes
详细参数:
- use-syslog:启用向 Syslog 消息记录日志。
- username:以 unbound 用户身份运行,该用户为默认用户。
- directory:Unbound 的默认工作目录为 '/etc/unbound' 目录。
- tls-cert-bundle:用于验证上游连接的证书。在基于 Debian 的发行版中,证书文件位于 '/etc/ssl/certs/ca-certificates.crt'。
- do-ip6:设为 'yes' 以在 IPv6 下运行 Unbound,或设为 'no' 以禁用 IPv6。
- interface:Unbound 将监听的网络接口或 IP 地址。你可以使用 IP 地址或接口名称(如 'eth0')。此外,你还可以通过添加类似 'IP-ADDRESS@PORT' 的格式在指定端口上运行。
- port:指定 Unbound 将运行的端口,客户端的连接将由该端口处理。默认的 DNS 端口为 53。
- prefetch:设为 'yes' 以启用对即将过期的消息缓存条目的预取。
- root-hints:包含根 DNS 服务器详细信息的文件。文件 '/usr/share/dns/root.hints' 由 'dns-root-data' 软件包提供。也可以从此处 'https://www.internic.net/domain/named.cache' 下载 root-hints 文件。
- harden-dnssec-stripped:设为 'yes' 以增强防护,避免接收到被剥离 DNSSEC 的数据。
启用 DNS 缓存
接下来,添加以下行以在你的 Unbound 安装中启用 DNS 缓存查询。
cache-max-ttl: 14400 cache-min-ttl: 1200
详细参数:
- cache-max-ttl:DNS 缓存中 RRSets 和消息的 TTL(生存时间)。单位为秒。
- cache-min-ttl:缓存的最小生存时间。默认值为 0,但你可以根据喜好更改,例如改为 '1200' 秒。不要将其设置为超过 1 小时,否则会因数据过期而引发问题。
Unbound 隐私与安全
现在你可以添加以下行来为 Unbound 设置基本的隐私与安全。
aggressive-nsec: yes hide-identity: yes hide-version: yes use-caps-for-id: yes
详细参数:
- aggressive-nsec:设为 'yes' 以启用激进 NSEC,它利用 DNSSEC NSEC 链来合成 NXDOMAIN 及其他否定响应。查看 IETF 关于 'NSEC' 的网页 https://www.ietf.org/archive/id/draft-ietf-dnsop-nsec-ttl-00.html。
- hide-identity:设为 yes 以禁用对 id.server 或 hostname.bind 的 bind 查询响应。
- hide-version:设为 yes 以禁用 version.server 和 version.bind 查询。
- use-caps-for-id:设为 yes 以在查询中启用 '0x20 编码' 来防范伪造攻击。
定义私有网络与访问控制列表(ACL)
接下来,你必须定义你网络的 private-address 和 ACL(访问控制列表)。根据你当前的网络环境,修改下面各行中的本地子网。
private-address: 192.168.0.0/16 private-address: 169.254.0.0/16 private-address: 172.16.0.0/12 private-address: 10.0.0.0/8 private-address: fd00::/8 private-address: fe80::/10 #control which clients are allowed to make (recursive) queries access-control: 127.0.0.1/32 allow_snoop access-control: ::1 allow_snoop access-control: 127.0.0.0/8 allow access-control: 192.168.5.0/24 allow
详细参数:
- private-address:定义你基础设施中的私有网络子网。只有 'private-domain' 和 'local-data' 名称才允许使用这些私有地址。
- access-control:定义访问控制,指定哪些客户端可以向 Unbound 服务器发起(递归)查询。参数 'allow' 将启用递归查询,而 'allow_snoop' 将同时启用递归和非递归查询。
设置本地域名
配置完 private-address 和访问控制列表后,你现在将为你的本地域名定义本地区域(zone)。这非常有用,尤其是当你的本地网络上有多个自托管应用时。你可以轻松定义你的域名或子域名,并将其指向特定的目标 IP 地址。
本例将为域名 'garden.lan' 创建类型为 'static' 的区域,然后你将通过 'local-data' 参数创建多个子域名。每个子域名将指向一个特定的 IP 地址,同时你还将通过 'local-data-ptr' 参数创建 PTR 记录。
# local zone local-zone: "garden.lan." static local-data: "firewall.garden.lan. IN A 10.0.0.1" local-data: "vault.garden.lan. IN A 10.0.0.2" local-data: "media.garden.lan. IN A 10.0.0.3" local-data: "docs.garden.lan. IN A 10.0.0.4" local-data: "wiki.garden.lan. IN A 10.0.0.5" local-data-ptr: "10.0.0.1 firewall.garden.lan" local-data-ptr: "10.0.0.2 vault.garden.lan" local-data-ptr: "10.0.0.3 media.garden.lan" local-data-ptr: "10.0.0.4 docs.garden.lan" local-data-ptr: "10.0.0.5 wiki.garden.lan"
详细参数:
- local-zone:在此定义本地域名。
- local-data:为子域名定义 A 记录以及将被解析的本地 IP 地址。
- local-data-ptr:为你的子域名定义 PTR 记录。
Unbound 性能调优
添加以下行以获得更高的性能。你可以根据当前环境调整下面的参数。
num-threads: 4 msg-cache-slabs: 8 rrset-cache-slabs: 8 infra-cache-slabs: 8 key-cache-slabs: 8 rrset-cache-size: 256m msg-cache-size: 128m so-rcvbuf: 8m
详细参数:
- num-threads:将创建的线程数量。该值应与服务器的 CPU 核心数相匹配。
- msg-cache-slabs:用于消息缓存的 slabs 数量。将其设为 8 以优化 Unbound 使用更多内存进行缓存。
- rrset-cache-slabs:用于 RRset 缓存的 slabs 数量。将其设为 8 以优化 Unbound 使用更多内存进行 RRSet 缓存。
- infra-cache-slabs:用于基础设施缓存的 slabs 数量。将其设为 8 以优化 Unbound 使用更多内存进行基础设施缓存。
- key-cache-slabs:用于密钥缓存的 slabs 数量。将其设为 8 以优化 Unbound 使用更多内存进行密钥缓存。
- rrset-cache-size:指定 RRSet 缓存的内存大小。本例使用 256MB,而默认值仅为 4MB。
- msg-cache-size:指定消息缓存的内存大小。本例使用 128MB,而默认值仅为 4MB。
- so-rcvbuf:将 DNS 端口 53/udp 的缓冲区大小设置为 8 MB。
将 Unbound 配置为支持 DNS-over-TLS(DoT)的 DNS 解析器
最后,添加一个新的 'forward-zone' 部分,将 Unbound 配置为本地网络的 DNS 解析器。本例使用启用了 DoT(DNS-over-TLS)的 Quad9 DNS 服务器。
forward-zone: name: "." forward-ssl-upstream: yes ## Also add IBM IPv6 Quad9 over TLS forward-addr: 9.9.9.9@853#dns.quad9.net forward-addr: 149.112.112.112@853#dns.quad9.net
详细参数:
- forward-zone:为 Unbound 定义转发区域。
- name:设为 "." 以转发所有 DNS 查询。
- forward-addr:使用特定的转发器来转发所有 DNS 查询。本例使用启用了 DNS-over-TLS(DoT)的 Quad9 DNS。
完成后保存并退出文件 '/etc/unbound/unbound.conf'。修改 Unbound 配置文件后,你现在可以重启 Unbound 服务并应用更改。
运行下面的命令检查并验证 Unbound 配置。如果成功,你将获得类似 'unbound-checkconf: no errors in /etc/unbound/unbound.conf' 的输出。
sudo unbound-checkconf
接下来,运行下面的 systemctl 命令重启 Unbound 服务并应用更改。
sudo systemctl restart unbound
现在你已经完成了 Unbound 配置,接下来你将设置 UFW 防火墙并开放默认的 DNS 端口 53。

配置 UFW 防火墙
在这一步中,你将在 Debian 服务器上设置 UFW 防火墙并开放 DNS 端口 53/udp。但在此之前,你必须通过 APT 从 Debian 仓库安装 UFW 软件包。
运行下面的 apt 命令将 UFW 防火墙安装到你的 Debian 服务器。出现提示时输入 y 并按 ENTER 继续。
sudo apt install ufw
输出:

UFW 安装完成后,你必须通过下面的命令在 UFW 上开放 OpenSSH 服务。然后,你可以将 DNS 端口 53/udp 添加到 UFW 防火墙。
sudo ufw allow OpenSSH
sudo ufw allow 53/udp
接下来,运行下面的命令启动并启用 UFW 防火墙服务。出现提示时输入 y 确认并按 ENTER 继续。
sudo ufw enable
输出 'Firewall is active and enabled on system startup' 确认 UFW 防火墙正在运行且已启用,这意味着 UFW 防火墙将在系统启动时自动启动。
输出:

现在运行下面的 ufw 命令来验证 UFW 防火墙的状态。你应该收到一个输出,显示 UFW 状态为 'active',且 OpenSSH 服务和 DNS 端口 53/udp 已启用。
sudo ufw status
输出:

通过 Rsyslog 和 Logrotate 记录 Unbound 日志
配置完 UFW 防火墙后,你现在将通过 rsyslog 和 logrotate 为 Unbound 设置日志文件。rsyslog 服务将为 Unbound 创建一个特定的日志文件,而 logrotate 将在特定时间轮转 Unbound 的日志文件。
使用下面的 nano 编辑器命令创建一个新的 Rsyslog 配置文件 '/etc/rsyslog.d/unbound.conf'。
sudo nano /etc/rsyslog.d/unbound.conf
将以下行添加到文件中。这样,Unbound 日志将被存储到 '/var/log/unbound.log'。
# Log messages generated by unbound application if $programname == 'unbound' then /var/log/unbound.log # stop processing it further & stop
完成后保存文件并退出编辑器。
现在运行下面的 systemctl 命令工具重启 'rsyslog' 服务并应用更改。
sudo systemctl restart rsyslog
接下来,你将为 Unbound 日志文件 '/var/log/unbound.log' 设置日志轮转。你可以通过 logrotate 服务来实现这一点。
使用下面的 nano 编辑器命令创建一个新的 logrotate 配置文件 '/etc/logrotate.d/unbound'。
sudo nano /etc/logrotate.d/unbound
将以下行添加到文件中。这将为 Unbound 日志文件 '/var/log/unbound.log' 创建按天进行的日志轮转。
/var/log/unbound.log {
daily
rotate 7
missingok
create 0640 root adm
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
完成后保存文件并退出编辑器。
现在运行下面的 systemctl 命令工具重启 logrotate 服务并应用更改。
sudo systemctl restart logrotate
至此,你已经成功安装并配置了 Unbound DNS 服务器,并通过 Rsyslog 和 Logrotate 配置了日志记录。Unbound 日志将被保存到文件 '/var/unbound/unbound.log'。

在 Linux 客户端上设置 DNS 解析器
在这一步中,你将学习如何在客户端机器上设置 DNS 解析器。这将向你展示适用于不同 Linux 发行版的两种方法。
对于 Ubuntu 客户端:Ubuntu 上的网络由 NetworkManager 管理。要设置 DNS 解析器,你可以将 NetworkManager 与 systemd-resolved 结合作为后端。对于 Debian 客户端:在 Debian 系统(精简版)上,网络由传统的配置文件 '/etc/network/interface' 处理。你可以将 DNS 解析器目录定义到 '/etc/network/interface' 文件中,或者使用在 Debian 服务器上默认可用的 systemd-resolved 服务。
适用于使用 NetworkManager 和 Systemd-resolved 的 Ubuntu 客户端
这适用于使用 NetworkManager 作为默认网络配置的 Ubuntu 用户。你将把 systemd-resolved 设置为 NetworkManager 上 DNS 服务器的后端。
使用下面的 nano 编辑器命令打开文件 '/etc/NetworkManager/NetworkManager.conf'。
sudo nano /etc/NetworkManager/NetworkManager.conf
取消注释 'dns' 参数,并将后端添加为 'systemd-resolved'。
dns=systemd-resolved
完成后保存并退出文件。
现在运行下面的 systemctl 命令重启 NetworkManager 服务并应用更改。
sudo systemctl restart NetworkManager
接下来,你将在 systemd-resolved 中定义 Unbound 本地 DNS。
使用下面的 nano 编辑器命令打开 systemd-resolved 配置文件 '/etc/systemd/resolved.conf'。
sudo nano /etc/systemd/resolved.conf
在 '[Resolve]' 部分,取消注释 'DNS' 参数,并输入你的 Unbound DNS 服务器的 IP 地址。
[Resolve] DNS= 192.168.5.20
完成后保存并退出文件。
接下来,运行下面的 systemctl 命令启动并启用 'systemd-resolved' 服务。
sudo systemctl start systemd-resolved
sudo systemctl enable systemd-resolved
现在通过下面的命令验证 'systemd-resolved' 服务的状态。你应该看到 systemd-resolved 已启用,并将在系统启动时自动运行。并且 'systemd-resolved' 服务的状态现在为正在运行。
sudo systemctl status systemd-resolved
你也可以通过下面的 'resolvectl' 命令验证你的 DNS 解析器配置。你应该看到默认解析器是你的 Unbound DNS 服务器,IP 地址为 '192.168.5.20'。
resolvectl status
适用于 Debian 客户端
对于 Debian 系统,你也可以使用 systemd-resolved 服务来设置 DNS 解析器。
使用下面的 nano 编辑器打开 systemd-resolved 配置文件 '/etc/systemd/resolved.conf'。
sudo nano /etc/systemd/resolved.conf
将 'DNS' 参数及其后跟的 Unbound 服务器 IP 地址添加到 '[Resolver]' 部分。
[Resolve] DNS=192.168.5.20
完成后保存文件并退出编辑器。
现在运行下面的 systemctl 命令启动并启用 systemd-resolved 服务。
sudo systemctl start systemd-resolved
sudo systemctl enable systemd-resolved
输出:

然后,验证 systemd-resolved 服务的状态以确保它正在运行。输出 'active (running)' 确认 systemd-resolved 正在运行,而输出 'loaded ../../../systemd-resolved.service; enabled;..' 确认该服务已启用。
sudo systemctl status systemd-resolved
输出:

你可以通过下面的 'resolvectl' 命令验证你的 DNS 解析器配置。你应该看到默认解析器是你的 Unbound DNS 服务器,IP 地址为 '192.168.5.20'。
resolvectl status
输出:

测试 Unbound DNS 服务器
运行下面的 dig 命令以确保 Unbound DNS 作为 DNS 解析器正常工作。参数 '@192.168.5.20' 确保你使用的是运行在 IP 地址 '192.168.5.20' 上的 Unbound DNS 服务器。
dig @192.168.5.20
成功时,你将收到来自根 DNS 服务器的应答,如下面的输出所示。此外,你会注意到头部输出中的 'ad'(authentic data,真实数据)标志,这意味着 DNSSEC 已启用。

接下来,运行下面的命令以确保客户端可以访问在线域名。
dig github.com
dig duckduckgo.com
成功时,你应该收到域名 'github.com' 和 'duckduckgo.com' 的 DNS 记录详细信息输出。你可以看到应答该查询的 DNS 解析器是 '127.0.0.53#53',即使用 Unbound 作为默认解析器的 systemd-resolved。此外,你可以看到每次查询的 'Query time'(查询时间),到域名 'github.com' 的 'Query time' 为 '1367',到 'duckduckgo.com' 的为 '1059'。
github.com 的输出:

duckduckgo.com 的输出:

如果你重新运行上面的 dig 命令,'Query time' 应该会减少。这确认了你的查询已被缓存,DNS 缓存正在工作。
dig github.com
dig duckduckgo.com
输出:


接下来,通过下面的 dig 命令验证本地域名或子域名。如果成功,每个子域名将指向在 Unbound 配置文件 '/etc/unbound/unbound.conf' 中配置的正确 IP 地址。
dig firewall.garden.lan +short
dig vault.garden.lan +short
dig media.garden.lan +short
输出:

现在运行下面的 dig 命令以确保 PTR 记录指向正确的域名。
dig -x 10.0.0.1 +short
dig -x 10.0.0.2 +short
dig -x 10.0.0.3 +short
输出:

最后,你还可以通过 tcpdump 验证 DoT(DNS over TLS)。将 'tcpdump' 软件包安装到你的 Unbound 服务器。
sudo apt install tcpdump
出现提示时输入 y 并按 ENTER 继续。

现在运行下面的 tcpdump 命令来监控接口 'eth0' 上 DoT 端口 853 的流量。在本例中,Unbound DNS 运行在 IP 地址 '192.168.5.20' 上,接口为 'eth0'。
tcpdump -vv -x -X -s 1500 -i eth0 'port 853'
切换到客户端机器,运行下面的命令通过 dig 命令访问外部/互联网域名。
dig google.com
输出:

之后,切换回 Unbound 服务器,你现在应该在 tcpdump 输出中看到类似的输出。

至此,你已经通过 Unbound 安装并配置了本地 DNS 服务器。此外,你还在 Ubuntu 客户端上通过 systemd-resolved 和 NetworkManager 配置了 DNS 解析器,在 Debian 客户端上通过 systemd-resolved 配置了 DNS 解析器。
结论
在本指南中,你已在 Debian 11 服务器上安装了 Unbound 本地 DNS 服务器。你启用了 DNS 缓存、DNSSEC(默认启用),配置了 private-address 和 ACL,通过 local-zone 添加了本地域名,然后将 Unbound 配置为支持 DoT(DNS-over-TLS)的 DNS 解析器。
此外,你还配置了基本的 DNS 隐私与安全,优化了 Unbound,并通过 rsyslog 和 logrotate 配置了 Unbound 日志。
在本指南的结尾,你还学习了如何通过 NetworkManager 和 systemd-resolved 在 Ubuntu 和 Debian 机器上设置 DNS 解析器。并且还学习了使用 dig 命令检查 DNS 服务器的基本用法。