前言
dns(domain name system,域名系统)是互联网最基础的服务之一,它的核心作用只有一个:把人类易记的域名转换成机器可读的 ip 地址。没有 dns,你访问网站就得记 142.250.70.78 而不是 google.com。
本文从实战出发,亲手搭建一套完整的 dns 服务体系,涵盖:
- 高速缓存 dns —— 加速域名解析,减少出口流量
- 正向解析(a 记录) —— 域名 → ipv4 地址
- 邮件交换记录(mx 记录) —— 指定邮件服务器
- 反向解析(ptr 记录) —— ip 地址 → 域名
- 多向解析(view 视图) —— 不同网段返回不同结果
- 主从同步(辅助 dns) —— 高可用、自动数据同步
一、高速缓存 dns(caching dns)
1.1 什么是缓存 dns?
当客户端向缓存 dns 发起查询时,缓存 dns 替它向互联网上的权威 dns 服务器递归查询,拿到结果后缓存到本地。下次同样的查询直接返回缓存结果,大幅提高解析速度。
工作流程图解:
客户端 → 缓存dns → 根dns → .com dns → baidu.com dns(权威)
↓ ↑
缓存 ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←
1.2 实验环境
| 主机名 | ip | 用途 |
|---|---|---|
| red(dns 服务器) | 192.168.17.138 | 部署缓存 dns |
| ub(客户端 1) | 192.168.17.131 | 测试查询 |
| ub2(客户端 2) | 192.168.17.137 | 测试查询 |
1.3 安装 bind 并启动服务
# 安装 bind 软件包(bind.x86_64 是 linux 上最主流的 dns 服务器软件) [root@bogon ~]# dnf install bind.x86_64 -y # 启用并立即启动 named 服务(named = name daemon,bind 的守护进程名) [root@bogon ~]# systemctl enable --now named
1.4 修改主配置文件
[root@bogon ~]# vim /etc/named.conf
options {
listen-on port 53 { any; }; # 监听所有网卡的 53 端口(默认只监 listening 127.0.0.1)
listen-on-v6 port 53 { ::1; }; # ipv6 保持监听本机
directory "/var/named"; # 区域文件的存放目录
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
secroots-file "/var/named/data/named.secroots";
recursing-file "/var/named/data/named.recursing";
allow-query { any; }; # 允许所有客户端向本机发起 dns 查询
forwarders { 144.144.144.144; }; # 指定上游 dns 服务器(缓存未命中时向谁转发)
};

重点参数说明:
| 参数 | 作用 |
|---|---|
| listen-on port 53 { any; } | 默认只监听 127.0.0.1,必须改为 any 才能对外服务 |
| allow-query { any; } | 访问控制,默认只允许本机,改为 any 开放给局域网 |
| forwarders | 上游 dns,缓存没命中的请求会转发给这个地址(可根据你的网络环境设为 114.114.114.114 或 8.8.8.8) |
1.5 重启并验证服务状态
[root@bogon ~]# systemctl restart named # 查看 named 是否正常监听端口 [root@bogon ~]# netstat -antlupe | grep named tcp 0 0 127.0.0.1:53 0.0.0.0:* listen 25 89111 35133/named tcp 0 0 192.168.17.138:53 0.0.0.0:* listen 25 89115 35133/named

看到 192.168.17.138:53 在 listen,说明 dns 服务器已正常对外提供服务。
1.6 客户端测试
在客户端 ub(192.168.17.131)上测试:
# dig 是最常用的 dns 查询工具,@ 指定要查询的 dns 服务器 root@qwe-virtual-machine:~# dig www.baidu.com @192.168.17.138

二、dns 权威解析部署
缓存 dns 是"代理查询",而下面要搭建的是权威 dns—— 自己管理一个域名,自己决定域名指向哪个 ip。
2.1 正向解析(a 记录)
作用:将域名解析为 ipv4 地址,这是 dns 最基础、最常用的功能。
2.1.1 添加区域声明
首先要告诉 named:“我负责管理 qwer.com 这个域”。
[root@bogon ~]# vim /etc/named.rfc1912.zones
在文件末尾添加:
zone "qwer.com" in {
type master; # 类型为主 dns 服务器
file "qwer.com.zone"; # 区域数据文件的路径(相对于 /var/named/)
allow-update { none; }; # 是否允许动态更新(这里不允许,安全考虑)
};

配置参数解读:
| 参数 | 含义 |
|---|---|
| type master | 本机是这个域的主 dns,数据由本机管理 |
| file "qwer.com.zone" | 指向 /var/named/qwer.com.zone 这个区域文件 |
| allow-update { none; } | 禁止外部动态更新 dns 记录(防止被篡改) |
2.1.2 创建区域数据文件
[root@bogon ~]# cd /var/named/ # -p 表示保留原文件的权限和属组(bind 对文件权限十分敏感) [root@bogon named]# cp -p named.localhost qwer.com.zone [root@bogon named]# vim qwer.com.zone
$ttl 1d
@ in soa admin.qwer.com. root.qwer.com. (
0 ; serial 序列号,从 0 开始,每次修改递增
1d ; refresh 辅 dns 刷新间隔(1 天)
1h ; retry 刷新失败后重试间隔(1 小时)
1w ; expire 辅 dns 数据过期时间(1 周)
3h ) ; minimum 否定缓存 ttl(3 小时)
ns dns.qwer.com. ; 声明权威 dns 服务器为 dns.qwer.com
dns a 192.168.17.138 ; dns.qwer.com 指向本机 ip
www a 192.168.17.138 ; www.qwer.com 指向本机 ip

逐行详解:
| 记录 | 含义 |
|---|---|
| $ttl 1d | 默认 ttl(time to live)为 1 天,告诉其他 dns 缓存这条记录多久 |
| @ | 代表当前域名(qwer.com),是 zone 语句里域名的简写 |
| soa | start of authority,起始授权记录,每个域必须有且只有一条 |
| ns dns.qwer.com. | nameserver 记录,指定该域的权威 dns 是哪个 |
| dns a 192.168.17.138 | a 记录,dns.qwer.com 指向 192.168.17.138 |
| www a 192.168.17.138 | a 记录,www.qwer.com 指向 192.168.17.138 |
⚠️ 注意域名结尾的点:dns.qwer.com. 最后一个点表示这是一个"完全限定域名(fqdn)",不加点的话 bind 会自动追加上 zone 名变成 dns.qwer.com.qwer.com。
2.1.3 重启 named 并测试
[root@bogon named]# systemctl restart named
客户端测试:
root@qwe-virtual-machine:~# dig www.qwer.com @192.168.17.138 ;; answer section: www.qwer.com. 86400 in a 192.168.17.138

成功! www.qwer.com 成功解析到 192.168.17.138。
2.2 邮件交换记录(mx 记录)
作用:mx 记录告诉发件服务器:“发往 user@qwer.com 的邮件应该投递到哪个邮件服务器”。
mx 记录 = 邮件服务器的"导航牌"。
2.2.1 添加 mx 记录
[root@bogon named]# vim qwer.com.zone
在文件末尾添加一行:
qwer.com. mx 5 192.168.17.138.
格式拆解:
域名 类型 优先级 邮件服务器域名 qwer.com. mx 5 192.168.17.138.
优先级(preference)说明:
- 数字越小优先级越高
- 如果配置了多条 mx:发件方会优先尝试
qwer.com. mx 5 mail1.qwer.com. qwer.com. mx 10 mail2.qwer.com.
mail1(优先级 5),失败后才尝试mail2(优先级 10) - 相同优先级可在多台服务器间负载均衡
⚠️ mx 记录的目标必须是域名,虽然上面例子直接写了 ip(简单演示),但生产环境标准的 mx 记录应该指向一个 a 记录域名,再通过 a 记录指向 ip:
qwer.com. mx 5 mail.qwer.com. mail a 192.168.17.138
重启并测试:
[root@bogon named]# systemctl restart named
root@qwe-virtual-machine:~# dig qwer.com mx @192.168.17.138

2.3 反向解析(ptr 记录)
作用:ptr 记录是 a 记录的"反向操作"——给定一个 ip 地址,查出它对应的域名。
为什么需要反向解析?
- 反垃圾邮件:接收方检查发件 ip 的 ptr 记录是否匹配发件域名。如果不匹配,邮件可能被标记为垃圾邮件或被拒收
- 日志审计:根据 ip 反查域名,更容易读懂访问来源
- 访问控制:某些服务(如 ssh、ftp)可根据 ptr 限制访问
2.3.1 添加反向区域声明
反向解析的 zone 名是 ip 反转 + .in-addr.arpa:
- 网段
192.168.17.0/24→ 反转17.168.192→ 得到17.168.192.in-addr.arpa
[root@localhost ~]# vim /etc/named.rfc1912.zones
zone "17.168.192.in-addr.arpa" in {
type master;
file "192.168.17.ptr";
allow-update { none; };
};
2.3.2 创建反向区域文件
[root@localhost ~]# cd /var/named/ # -p 保留权限,named.loopback 是反向区域文件的模板 [root@localhost named]# cp -p named.loopback 192.168.17.ptr [root@localhost named]# vim 192.168.17.ptr
$ttl 1d
@ in soa admin.qwer.com. root.qwer.com. (
0 ; serial
1d ; refresh
1h ; retry
1w ; expire
3h ) ; minimum
ns dns.qwer.com. ; 权威 dns 服务器
dns a 192.168.17.138 ; 必须有一条 a 记录指向 dns 本身
111 ptr haha.qwer.com. ; 192.168.17.111 → haha.qwer.com
重点说明:
111是 ip 地址192.168.17.111的最后一段,bind 会自动拼接成111.17.168.192.in-addr.arpaptr haha.qwer.com.—— 表示 ip192.168.17.111解析为域名haha.qwer.com.- 反向区域文件中必须有对应的 a 记录(
dns a 192.168.17.138),否则 bind 会报错
2.3.3 测试反向解析
root@qwe-virtual-machine:~# dig -x 192.168.17.111 @192.168.17.138 ;; answer section: 111.17.168.192.in-addr.arpa. 86400 in ptr haha.qwer.com.

参数 -x 是 dig 的反向查询快捷方式,相当于帮你把 ip 反转成 in-addr.arpa 格式。
三、dns 多向解析
3.1 什么是多向解析?
同一个 dns 服务器,根据客户端来源 ip 的不同,返回不同的解析结果。这在实际生产环境中非常实用:
| 客户端网段 | 查询 www.example.com | 返回的 ip | 目的 |
|---|---|---|---|
| 内网 16 网段(192.168.16.x) | → | 10.16.0.10 | 访问内网服务器 |
| 内网 15 网段(192.168.15.x) | → | 10.15.0.10 | 访问就近的内网服务器 |
| 外网(互联网) | → | 1.2.3.4 | 访问公网入口 |
为什么要这么做?
- 内网用户不需要绕到外网再回来,直接解析到内网 ip,速度快、流量省
- 不同网段可以指向不同服务器(负载分担 / 就近接入)
- 外网用户解析到公网入口,走正常的外网访问路径
3.2 实验环境
| 主机名 | ip | 用途 |
|---|---|---|
| dns 服务器 | 192.168.17.1 | 部署多向解析(view),同时服务 16 和 15 网段 |
| 客户端 a | 192.168.16.100 | 16 网段用户 |
| 客户端 b | 192.168.15.100 | 15 网段用户 |
3.3 配置多向解析
3.3.1 主配置文件启用 view
bind 的 view 配置写在 /etc/named.conf 中。注意:一旦使用了 view,所有的 zone 都必须放在 view 内部。
[root@dns ~]# vim /etc/named.conf
整体结构如下:
options {
listen-on port 53 { any; };
listen-on-v6 port 53 { ::1; };
directory "/var/named";
allow-query { any; };
};
# ---------- 视图 1:16 网段 ----------
view "lan16" {
match-clients { 192.168.16.0/24; }; # 匹配来自 16 网段的请求
zone "." in {
type hint;
file "named.ca"; # 根域提示(每个 view 都要有)
};
zone "example.com" in {
type master;
file "example.com.zone.lan16"; # 16 网段专用的区域文件
};
};
# ---------- 视图 2:15 网段 ----------
view "lan15" {
match-clients { 192.168.15.0/24; }; # 匹配来自 15 网段的请求
zone "." in {
type hint;
file "named.ca";
};
zone "example.com" in {
type master;
file "example.com.zone.lan15"; # 15 网段专用的区域文件
};
};
# ---------- 视图 3:其他(外网) ----------
view "external" {
match-clients { any; }; # 其他所有来源
zone "." in {
type hint;
file "named.ca";
};
zone "example.com" in {
type master;
file "example.com.zone.external"; # 外网看到的区域文件
};
};
配置详解:
| 配置 | 作用 |
|---|---|
| view "lan16" | 视图名称,可自定义,无实际功能影响 |
| match-clients { 192.168.16.0/24; } | 匹配规则——只有源 ip 匹配的客户端才会进入这个 view |
| match-clients { any; } | 兜底匹配——必须放在最后,匹配所有不满足上面条件的客户端 |
| 多个 view 的匹配顺序 | bind 从上到下依次匹配,命中了就进入,不再继续 |
3.3.2 创建三个区域文件
每个 view 引用了不同的区域文件,现在分别创建:
16 网段区域文件——给内网 16 网段的用户看:
[root@dns ~]# cd /var/named/ [root@dns named]# vim example.com.zone.lan16
$ttl 1d
@ in soa admin.example.com. root.example.com. (
0 ; serial
1d ; refresh
1h ; retry
1w ; expire
3h ) ; minimum
ns dns.example.com.
dns a 192.168.17.1
www a 10.16.0.10 # 16 网段用户访问 www,返回内网 10.16.0.10
15 网段区域文件——给内网 15 网段的用户看:
[root@dns named]# vim example.com.zone.lan15
$ttl 1d
@ in soa admin.example.com. root.example.com. (
0 ; serial
1d ; refresh
1h ; retry
1w ; expire
3h ) ; minimum
ns dns.example.com.
dns a 192.168.17.1
www a 10.15.0.10 # 15 网段用户访问 www,返回 10.15.0.10
外网区域文件——给互联网用户看:
[root@dns named]# vim example.com.zone.external
$ttl 1d
@ in soa admin.example.com. root.example.com. (
0 ; serial
1d ; refresh
1h ; retry
1w ; expire
3h ) ; minimum
ns dns.example.com.
dns a 192.168.17.1
www a 1.2.3.4 # 外网用户访问 www,返回公网 ip
⚠️ 注意文件名:bind 对区域文件的名称没有强制要求,但建议用有意义的命名区分不同视图,避免混淆。
3.3.3 重启 named
[root@dns named]# systemctl restart named
3.4 多向解析的核心要点
| 要点 | 说明 |
|---|---|
| 匹配顺序 | view 按 named.conf 中定义的顺序从上到下匹配,命中即止 |
| 兜底 view | 最后一个 view 必须用 match-clients { any; },防止没有匹配的客户端被拒绝 |
| 根域提示 | 每个 view 里都要配 zone "." { type hint; file "named.ca"; },否则递归查询失效 |
| 区域文件独立 | 不同 view 的区域文件互不干扰,可以同名区域不同内容 |
| 安全隔离 | 内网用户解析不到公网 ip,外网用户也看不到内网拓扑 |
四、主从 dns 同步(辅助 dns)
4.1 为什么需要主从架构?
单台 dns 服务器会面临单点故障——服务器宕机,整个域名解析就瘫痪。主从架构解决了这个问题:
- 主 dns(master):数据源,可读可写
- 从 dns(slave):从主 dns 同步数据,只读
- 客户端可以配置两个 dns,一个宕机自动切到另一个
4.2 实验环境
| 主机名 | ip | 角色 |
|---|---|---|
| node1 | 172.25.254.10 | dns 主服务器(master),拥有 timinglee.org 的完整数据 |
| node2 | 172.25.254.20 | dns 从服务器(slave),从 node1 同步数据 |
4.3 配置主 dns(node1)
4.3.1 安装 bind
[root@node1 ~]# dnf install bind -y
4.3.2 修改主配置文件
[root@node1 ~]# vim /etc/named.conf
options {
listen-on port 53 { any; }; # 监听所有网卡
listen-on-v6 port 53 { ::1; };
directory "/var/named";
allow-query { any; }; # 允许所有客户端查询
recursion yes;
};
4.3.3 添加主区域声明
[root@node1 ~]# vim /etc/named.rfc1912.zones
zone "timinglee.org" in {
type master;
file "timinglee.org.zone";
allow-update { none; };
allow-transfer { 172.25.254.20; }; # 仅允许从 dns node2 来同步数据
};
⚠️ allow-transfer 是关键:如果不加这一行,从 dns 请求区域传输时会被拒绝,无法同步任何数据。
4.3.4 创建区域文件
[root@node1 ~]# cd /var/named/ [root@node1 named]# cp -p named.localhost timinglee.org.zone [root@node1 named]# vim timinglee.org.zone
$ttl 1d
@ in soa admin.timinglee.org. root.timinglee.org. (
2026071901 ; serial
1d ; refresh
1h ; retry
1w ; expire
3h ) ; minimum
ns dns.timinglee.org.
dns a 172.25.254.10
timinglee a 172.25.254.254
[root@node1 named]# systemctl restart named
4.4 配置从 dns(node2)
4.4.1 安装 bind
[root@node2 ~]# dnf install bind -y
4.4.2 修改主配置文件
从 dns 的 named.conf 配置与主 dns 类似,开放监听和查询权限:
[root@node2 ~]# vim /etc/named.conf
options {
listen-on port 53 { any; };
listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
secroots-file "/var/named/data/named.secroots";
recursing-file "/var/named/data/named.recursing";
allow-query { any; };
};
4.4.3 添加从区域声明
[root@node2 ~]# vim /etc/named.rfc1912.zones
zone "timinglee.org" in {
type slave; # 类型为从 dns
masters { 172.25.254.10; }; # 指定主 dns 的 ip
file "slaves/timinglee.org.zone"; # 同步来的数据存放位置
};
file "slaves/timinglee.org.zone" —— 为什么是 slaves/ 目录?因为 named 的 selinux 策略只允许从 dns 在 slaves/ 目录下创建文件。
4.4.4 启动从 dns
[root@node2 ~]# systemctl enable --now named
4.5 测试主从同步是否成功
在**从 dns(node2)**上查询 timinglee.org 域内的域名,看看数据是否同步过来了:
[root@node2 ~]# dig timinglee.timinglee.org @172.25.254.20 ; <<>> dig 9.16.23-rh <<>> timinglee.timinglee.org @172.25.254.20 ;; flags: qr aa rd ra; query: 1, answer: 1, authority: 0, additional: 1 ;; answer section: timinglee.timinglee.org. 86400 in a 172.25.254.254
status: noerror + answer section 返回了正确的 ip 172.25.254.254,主从同步成功 🎉
此时查看从 dns 的 slaves 目录,可以看到数据文件已被自动创建:
[root@node2 ~]# ls -l /var/named/slaves/ -rw-r--r--. 1 named named 432 jul 19 15:45 timinglee.org.zone
4.6 主 dns 数据变更后自动通知从 dns
问题:默认配置下,主 dns 修改了区域数据后,从 dns 要等 1 天(refresh 字段) 才会去检查并同步。更新跟不上变化。
解决方案:在主 dns 上配置 also-notify,当数据变更时主动通知从 dns 过来拉取最新数据。
4.6.1 主 dns 添加通知配置
[root@node1 named]# vim /etc/named.rfc1912.zones
zone "timinglee.org" in {
type master;
file "timinglee.org.zone";
allow-update { none; };
allow-transfer { 172.25.254.20; }; # 允许从 dns 同步
also-notify { 172.25.254.20; }; # 数据变更时主动通知这个从 dns
};
4.6.2 修改区域文件并递增序列号
模拟一个变更——将 timinglee 的 a 记录从 172.25.254.254 改为 172.25.254.222:
[root@node1 named]# vim /var/named/timinglee.org.zone
$ttl 1d
@ in soa admin.timinglee.org. root.timinglee.org. (
2026071903 ; serial ← 关键:每次修改都要递增这个数字!
1d ; refresh
1h ; retry
1w ; expire
3h ) ; minimum
ns dns.timinglee.org.
dns a 172.25.254.10
timinglee a 172.25.254.222 ; 从 254 改为 222
timinglee.org. mx 5 172.25.254.10.
serial(序列号)为什么重要? 从 dns 通过比较序列号来判断数据是否更新。主 dns 序列号更大 → 从 dns 发起同步。改了记录但忘记递增序列号,从 dns 永远不会同步。
4.6.3 重启主 dns
[root@node1 named]# systemctl restart named
4.6.4 验证自动同步
在从 dns(node2)上再次查询,此刻从 dns 没有做任何操作,但数据已经刷新:
[root@node2 ~]# dig timinglee.timinglee.org @172.25.254.20 ;; answer section: timinglee.timinglee.org. 86400 in a 172.25.254.222
ip 从原来的 172.25.254.254 更新成了 172.25.254.222,also-notify 实时同步成功!
五、知识点总结
dns 记录类型速查表
| 记录类型 | 方向 | 格式示例 | 用途 |
|---|---|---|---|
| a | 域名 → ipv4 | www.example.com. a 192.168.1.10 | 网站访问基础 |
| aaaa | 域名 → ipv6 | www.example.com. aaaa 2001:db8::1 | ipv6 访问 |
| mx | 域名 → 邮件服务器 | example.com. mx 10 mail.example.com. | 邮件路由 |
| ptr | ip → 域名 | 10.1.168.192.in-addr.arpa. ptr www.example.com. | 反查验证 |
| ns | 域名 → dns 服务器 | example.com. ns ns1.example.com. | 声明权威 dns |
| soa | 起始授权 | @ soa admin.example.com. root.example.com. (...) | 区域管理参数 |
| cname | 域名 → 别名 | www.example.com. cname example.com. | 域名别名 |
主从 dns 同步流程
1. 管理员修改主 dns 区域文件 2. 递增 serial 序列号 3. 重启 named 4. also-notify 主动通知从 dns 5. 从 dns 比较序列号,发现更新 6. 从 dns 发起区域传输(axfr/ixfr) 7. 从 dns 数据同步完成
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论