在 Ubuntu 中部署和配置 DNS 服务

域名服务(DNS)负责在 IP 地址和完全限定域名(FQDN)之间转换,让人们无需记忆 IP。运行 DNS 的计算机称为域名服务器。Ubuntu 提供 Berkeley Internet Naming Daemon(BIND),它是 Linux 上常见的域名服务器程序。

安装 DNS

安装 bind9:

sudo apt install bind9

dnsutils 包包含测试与排查工具,通常已经安装,也可以执行:

sudo apt install dnsutils

配置概览

BIND9 有多种配置方式,常见的是缓存服务器、主服务器与从服务器。

  • 缓存服务器负责查询并记住结果,下次可复用。
  • 主服务器从本机文件读取某个区域的数据,是该区域的权威服务器。
  • 从服务器从其他权威服务器获取区域数据。

配置文件

文件位于 /etc/bind。主配置 named.conf 按软件包默认结构包含:

  • named.conf.options:全局选项。
  • named.conf.local:自定义区域。
  • named.conf.default-zones:localhost、其反向区域和根提示等默认区域。

根服务器信息由 dns-root-data 包的 /usr/share/dns/root.hints 提供,并由默认区域配置引用。Ubuntu 18.04 LTS 及更早时期使用 /etc/bind/db.root。

同一服务器可以同时承担缓存、主服务器与从服务器角色,取决于具体区域。例如对一个区域权威负责,对另一个区域提供从服务,同时为局域网缓存查询。

配置缓存域名服务器

默认配置已作为缓存服务器运行。编辑 /etc/bind/named.conf.options,在 options 中添加运营商 DNS 的 forwarders:

options {
    forwarders {
        1.2.3.4;
        5.6.7.8;
    };
};

将示例地址替换为真实 DNS 服务器地址。然后重启:

sudo systemctl restart bind9.service

测试方式见下文 dig 部分。

配置主服务器

本节为 example.com 配置主服务器,可以替换为自己的 FQDN。

正向区域文件

编辑 /etc/bind/named.conf.local,添加:

zone "example.com" {
    type master;
    file "/etc/bind/db.example.com";
};

注意:如果通过 DDNS 等方式自动更新区域文件,应使用 /var/lib/bind/db.example.com,而不是 /etc/bind 下的路径。

创建 /etc/bind/db.example.com。直到 Ubuntu 25.04,可从 db.local 等模板复制。

填写服务器 FQDN,并保留结尾点号;填写域名服务器 IP,以及有效邮箱,但用点号替换 @,末尾也加点。例如 root@example.com 写为 root.example.com.。可用分号添加注释。

为基础域名 example.com 和本例域名服务器 ns.example.com 创建 A 记录:

;
; BIND data file for example.com
;
$TTL    604800
@       IN      SOA     example.com. root.example.com. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL

@       IN      NS      ns.example.com.
@       IN      A       192.168.1.10
@       IN      AAAA    2001:db8::10
ns      IN      A       192.168.1.10

每次修改区域文件都必须增加 Serial。如果重启前一次做了多项修改,只需增加一次。可以继续在文件底部添加记录,类型说明见下文。

提示:很多管理员用最后修改日期作为序列号,例如 2020012100,格式为 yyyymmddss,ss 是当日序号。

修改完成后重启生效:

sudo systemctl restart bind9.service

反向区域文件

正向解析已能将名称转为 IP,还需要反向区域把地址转为名称。在 named.conf.local 添加:

zone "1.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192";
};

将 1.168.192 替换为所用网络前三个八位组的反向排列。db.192 文件名也应按网络第一个八位组相应命名。

创建 db.192,并修改与正向区域相同的选项:

;
; BIND reverse data file for local 192.168.1.XXX net
;
$TTL    604800
@       IN      SOA     ns.example.com. root.example.com. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
@       IN      NS      ns.
10      IN      PTR     ns.example.com.

反向区域每次修改也要递增 Serial。正向文件中每个不同地址的 A 记录,都需要对应 PTR 记录。

创建后重启:

sudo systemctl restart bind9.service

配置从服务器

强烈建议配置从服务器,确保主服务器不可用时域名仍可解析。

先在主服务器的正反向区域中添加 allow-transfer:

zone "example.com" {
    type master;
    file "/etc/bind/db.example.com";
    allow-transfer { 192.168.1.11; };
};
    
zone "1.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192";
    allow-transfer { 192.168.1.11; };
};

192.168.1.11 替换为从服务器地址,然后重启主服务器:

sudo systemctl restart bind9.service

在从服务器同样安装 bind9,再向 named.conf.local 添加:

zone "example.com" {
    type secondary;
    file "db.example.com";
    masters { 192.168.1.10; };
};        
          
zone "1.168.192.in-addr.arpa" {
    type secondary;
    file "db.192";
    masters { 192.168.1.10; };
};

将 192.168.1.10 替换为主服务器地址,然后重启从服务器:

sudo systemctl restart bind9.service

/var/log/syslog 应出现类似内容。原文为排版对部分行进行了换行:

client 192.168.1.10#39448: received notify for zone '1.168.192.in-addr.arpa'
zone 1.168.192.in-addr.arpa/IN: Transfer started.
transfer of '100.18.172.in-addr.arpa/IN' from 192.168.1.10#53:
 connected using 192.168.1.11#37531
zone 1.168.192.in-addr.arpa/IN: transferred serial 5
transfer of '100.18.172.in-addr.arpa/IN' from 192.168.1.10#53:
 Transfer completed: 1 messages, 
6 records, 212 bytes, 0.002 secs (106000 bytes/sec)
zone 1.168.192.in-addr.arpa/IN: sending notifies (serial 5)
    
client 192.168.1.10#20329: received notify for zone 'example.com'
zone example.com/IN: Transfer started.
transfer of 'example.com/IN' from 192.168.1.10#53: connected using 192.168.1.11#38577
zone example.com/IN: transferred serial 5
transfer of 'example.com/IN' from 192.168.1.10#53: Transfer completed: 1 messages, 
8 records, 225 bytes, 0.002 secs (112500 bytes/sec)

注意:只有主服务器 Serial 大于从服务器,才会传送区域。要主动通知其他从服务器变更,可加入 also-notify:

zone "example.com" {
    type master;
    file "/etc/bind/db.example.com";
    allow-transfer { 192.168.1.11; };
    also-notify { 192.168.1.11; }; 
};

zone "1.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192";
    allow-transfer { 192.168.1.11; };
    also-notify { 192.168.1.11; }; 
};

非权威区域文件默认位于 /var/cache/bind/。AppArmor 也允许 named 写入此目录,更多说明见 AppArmor 文档。

测试配置

resolv.conf

先将域名服务器 IP 加入客户端解析配置。主服务器自身以及另一台主机都应配置,以便交叉确认。具体方法见 DNS 客户端配置。最终 /etc/resolv.conf 的 nameserver 应指向 127.0.0.53,并包含搜索域:

nameserver  127.0.0.53
search example.com

查看本地解析器实际使用哪个 DNS:

resolvectl status

也应在客户端配置从服务器地址,防范主服务器不可用。

dig

安装 dnsutils 后,可用 dig 测试。首先查询回环地址,确认 BIND9 监听 53 端口:

dig -x 127.0.0.1
;; Query time: 1 msec
;; SERVER: 192.168.1.10#53(192.168.1.10)

缓存服务器可以查询外部域名,观察末尾耗时:

dig ubuntu.com
;; Query time: 49 msec

再次查询,时间应缩短:

;; Query time: 1 msec

ping

使用 ping 发送 ICMP 回显,展示应用如何通过 DNS 解析主机名:

ping example.com

原文给出的解析输出示例如下:

PING ns.example.com (192.168.1.10) 56(84) bytes of data.
64 bytes from 192.168.1.10: icmp_seq=1 ttl=64 time=0.800 ms
64 bytes from 192.168.1.10: icmp_seq=2 ttl=64 time=0.813 ms

named-checkzone

bind9 包内的 named-checkzone 可在重启生效前检查区域文件。测试正向区域:

named-checkzone example.com /etc/bind/db.example.com
zone example.com/IN: loaded serial 6
OK

测试反向区域:

named-checkzone 1.168.192.in-addr.arpa /etc/bind/db.192
zone 1.168.192.in-addr.arpa/IN: loaded serial 3
OK

你的序列号可能与示例不同。

临时启用查询日志

rndc 无需重启或修改文件,就能快速开关查询日志。启用:

sudo rndc querylog on

关闭:

sudo rndc querylog off

默认发送到 syslog,并显示在 /var/log/syslog:

Jan 20 19:40:50 new-n1 named[816]: received control channel command 'querylog on'
Jan 20 19:40:50 new-n1 named[816]: query logging is now on
Jan 20 19:40:57 new-n1 named[816]: client @0x7f48ec101480 192.168.1.10#36139 (ubuntu.com): query: ubuntu.com IN A +E(0)K (192.168.1.10)

注意:查询日志量可能非常大。

日志配置

BIND9 日志选项很多,最重要的是 channel 与 category,分别决定日志位置和内容。未指定时默认:

logging {
     category default { default_syslog; default_debug; };
     category unmatched { null; };
};

若希望把 DNS 查询调试信息写入独立文件,需要配置目标 channel 与记录查询的 category。在 named.conf.local 添加:

logging {
    channel query.log {
        file "/var/log/named/query.log";
        severity debug 3;
    };
    category queries { query.log; };
};

debug 级别可设为 1–3,未指定时默认为 1。

named 以 bind 用户运行,因此需要创建目录并更改所有者:

sudo mkdir /var/log/named
sudo chown bind:bind /var/log/named

然后重启:

sudo systemctl restart bind9.service

此后 query.log 应不断写入查询信息。更高级的配置见文末资料。

常见记录类型

A 记录

建立主机名与 IPv4 地址的对应关系:

www      IN    A      192.168.1.12

CNAME 记录

为现有 A 记录创建别名。原文提醒,不应创建指向另一条 CNAME 的 CNAME:

web     IN    CNAME  www

MX 记录

指定邮件投递服务器,目标必须指向 A 记录,而不是 CNAME:

@       IN    MX  1   mail.example.com.
mail    IN    A       192.168.1.13

NS 记录

指定保存区域副本的服务器,用于定义主、从服务器。目标应有 A 记录,不能是 CNAME:

@       IN    NS     ns.example.com.
@       IN    NS     ns2.example.com.
ns      IN    A      192.168.1.10
ns2     IN    A      192.168.1.11

进一步阅读


原文:Domain Name Service (DNS)。作者/维护者:Canonical Ubuntu Server 文档贡献者。本文为原文的中文译文;代码保留原文内容。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容