1. 为什么内网自建DNS比你想的更值得折腾很多团队在规模小的时候,习惯直接用路由器或者运营商下发的DNS,机器少、访问目标单一,确实感觉不出问题。可一旦内网设备超过二三十台,或者开始有微服务、容器、测试环境、预发布环境这些需要靠域名互相寻址的场景,靠hosts文件和IP直连就会迅速变成一场灾难。改一台机器的hosts要登录一次,换一个IP要通知一圈人,测试环境域名和线上冲突更是家常便饭。这时候,自建一套内网DNS几乎是绕不开的选择。在Linux上做内网DNS,BIND(Berkeley Internet Name Domain)是最经典也最稳的方案。它足够老,老到几乎所有Linux发行版都自带或者一条命令就能装;它也足够强,强到全球根域名体系里相当一部分环节都在跑它。对于内网场景,BIND提供的主从(Master/Slave)复制能力尤其关键——主节点负责写记录,从节点自动同步,主节点挂了从节点还能继续提供解析,这就是内网DNS高可用的最低成本实现。这篇内容面向的是有一定Linux基础、想在内网快速搭起一套可用DNS主从架构的运维或开发人员。我会从BIND的安装、主从配置、区域文件编写、同步验证,一路讲到实际踩过的坑和排查思路。整套流程在几台普通Linux机器上就能复现,不需要额外硬件,也不需要复杂的编排系统。读完你至少能做到:内网域名自己说了算,主从自动同步,出问题知道从哪查。需要先说明一点,本文所有示例中的IP段、域名、主机名都是虚构的占位符,你在实际部署时替换成自己环境的真实值即可。下面进入正题。2. 动手之前先把BIND主从的账算清楚2.1 主从模式到底解决了什么问题单台DNS服务器最大的问题是单点故障。一旦这台机器宕机、网络抖动或者BIND进程崩溃,整个内网所有依赖域名解析的服务都会跟着遭殃。你可能会说,那我配两个DNS地址不就行了?问题在于,如果两台DNS各自独立维护,记录不一致,客户端查询结果就会随机漂移,排查起来极其痛苦。主从模式的核心价值就在于:写入只发生在主节点,从节点通过区域传送(Zone Transfer)自动拉取全量记录。这样既保证了数据一致性,又实现了冗余。客户端配置里把主从两个IP都写上,主节点不可用时从节点顶上,解析不中断。从实现角度看,BIND的主从同步依赖的是SOA记录中的serial字段。从节点定期检查主节点的serial,一旦发现主节点的serial比自己大,就触发一次区域传送。这个机制简单但有效,理解它是后面排查同步问题的关键。2.2 部署前需要确认的几件事在真正敲命令之前,有几项准备工作必须先确认,否则后面会反复返工。第一是网络规划。你需要明确主从两台机器的IP、内网要使用的域名后缀(比如internal.example.lan这种虚构后缀)、以及客户端会用哪些网段。域名后缀建议不要用公网真实存在的顶级域,避免解析时产生歧义。第二是端口和防火墙。DNS标准端口是53,TCP和UDP都要放行。主从之间还需要允许TCP 53用于区域传送。很多同步失败最后查出来都是防火墙只放了UDP没放TCP。第三是时间同步。主从机器的系统时间如果偏差太大,日志时间戳会对不上,排查问题时非常难受。建议部署前先确认两台机器时间基本一致。第四是SELinux和AppArmor。部分发行版默认开启的安全模块会阻止BIND绑定端口或读取区域文件,如果遇到莫名其妙的权限拒绝,先检查这里。下面这张表把关键准备项列清楚,方便对照检查:准备项主节点从节点说明静态IP需要需要避免DHCP导致地址漂移53端口TCP/UDP放行放行区域传送依赖TCP 53时间同步建议建议日志排查更顺畅安全模块确认放行确认放行避免权限拒绝域名后缀统一规划统一规划主从必须一致2.3 安装BIND:不同发行版的差异BIND在不同发行版上的包名和配置文件路径略有差异,这是新手最容易困惑的地方。我把它整理成一张对照表:发行版系安装命令主配置路径区域文件目录Debian/Ubuntuapt install bind9/etc/bind/named.conf/etc/bind/RHEL/CentOSyum install bind/etc/named.conf/var/named/通用源码编译安装自定义自定义以Debian系为例,安装完成后BIND会自动注册为系统服务,服务名通常是bind9或named。安装后先别急着改配置,用named -v确认版本,用systemctl status看服务状态,确保基础环境是干净的。提示:如果你的发行版默认装了systemd-resolved并占用了53端口,BIND会启动失败。这种情况需要先停用或调整该服务,把53端口让出来。3. 主节点配置:从named.conf到区域文件3.1 主配置文件的整体结构BIND的主配置文件通常由三部分组成:全局选项(options)、日志配置(logging)、区域声明(zone)。对于内网场景,我们重点关注options和zone两块。一个精简但完整的主节点配置大致长这样(以虚构域名internal.example.lan为例):options { listen-on port 53 { 127.0.0.1; 10.10.0.1; }; listen-on-v6 { none; }; directory "/var/named"; allow-query { 10.10.0.0/24; 127.0.0.1; }; allow-transfer { 10.10.0.2; }; recursion yes; forwarders { 8.8.8.8; }; }; zone "internal.example.lan" IN { type master; file "internal.example.lan.zone"; allow-update { none; }; };这里有几个参数值得展开说。listen-on指定BIND监听的地址,内网场景建议只监听内网IP和本地回环,不要监听any,减少暴露面。allow-query限制哪些网段可以查询,防止被当成开放解析器滥用。allow-transfer是主从同步的关键,只允许从节点IP发起区域传送,这是安全底线。forwarders的作用是:当查询的域名不在本地区域内时,转发给上游DNS。内网场景下这个配置让BIND既能解析内网域名,又能解析公网域名,一举两得。3.2 区域文件怎么写才不出错区域文件是真正存放记录的地方,格式上最容易出错。一个标准的正向区域文件包含SOA、NS、A、CNAME、MX等记录类型。下面是一个可用的示例:$TTL 3600 @ IN SOA ns1.internal.example.lan. admin.internal.example.lan. ( 2024010101 ; serial 3600 ; refresh 1800 ; retry 604800 ; expire 86400 ; minimum ) @ IN NS ns1.internal.example.lan. @ IN NS ns2.internal.example.lan. ns1 IN A 10.10.0.1 ns2 IN A 10.10.0.2 web IN A 10.10.0.10 db IN A 10.10.0.11 cache IN CNAME web.internal.example.lan.这里有几个细节必须强调。serial字段是主从同步的触发器,每次修改记录后必须手动递增,否则从节点不会同步。建议用日期加序号的方式,比如2024010101表示2024年1月1日第1次修改,这样既直观又不容易重复。SOA记录末尾的域名必须带点,admin.internal.example.lan.最后那个点表示这是完全限定域名,漏掉点会导致解析异常。同理,NS记录里的域名也要带点。这是新手最常踩的坑之一。CNAME记录不能和其他记录共存。比如你不能给cache同时配CNAME和A记录,这是DNS协议层面的限制,不是BIND的问题。3.3 配置检查与启动改完配置别急着重启服务,先用BIND自带的检查工具验证语法:named-checkconf /etc/named.conf named-checkzone internal.example.lan /var/named/internal.example.lan.zonenamed-checkconf检查主配置语法,named-checkzone检查区域文件语法。两个命令都通过后再重启服务:systemctl restart named systemctl status named服务起来后,用dig或nslookup在本地验证:dig @127.0.0.1 web.internal.example.lan如果返回正确的A记录,说明主节点基本可用。如果返回SERVFAIL或REFUSED,先看日志/var/log/messages或journalctl -u named,日志里通常有明确原因。4. 从节点配置:让同步真正跑起来4.1 从节点的zone声明与主节点不同从节点的配置结构和主节点类似,但zone部分的type要改成slave,并且要指定masters指向主节点:zone "internal.example.lan" IN { type slave; file "slaves/internal.example.lan.zone"; masters { 10.10.0.1; }; };注意file的路径。从节点的区域文件是自动生成的,不需要你手动创建,BIND从主节点拉取后会自动写入这个路径。所以这个目录必须对BIND进程可写,否则同步会失败。Debian系默认在/var/cache/bind/,RHEL系在/var/named/slaves/,具体以你的配置为准。从节点的options里,allow-transfer可以设为none,因为从节点不需要再向别人传送。allow-query则要和主节点保持一致,保证客户端能正常查询。4.2 区域传送的触发与验证从节点启动后,会主动向主节点发起一次区域传送。触发条件是:从节点本地没有区域文件,或者主节点的serial比本地大。传送成功后,从节点会在指定路径生成区域文件。验证同步是否成功,有几个层次的方法。最直接的是看从节点上区域文件是否生成:ls -l /var/named/slaves/如果文件存在且大小不为零,说明至少传送过一次。再进一步,用dig直接查从节点:dig @10.10.0.2 web.internal.example.lan返回和主节点一致的结果,说明从节点已经在正常提供服务。还可以在主节点上主动触发一次传送来测试:dig @10.10.0.1 internal.example.lan AXFR这个命令会列出整个区域的所有记录。如果返回完整记录列表,说明区域传送通道是通的。如果返回Transfer failed,就要去查allow-transfer配置和防火墙。4.3 同步失败时按这个顺序排查主从同步失败是内网DNS最常见的故障,我把它整理成一个排查顺序,照着走基本能定位:排查步骤检查内容常见问题1主节点allow-transfer从节点IP没加进去2防火墙TCP 53只放了UDP没放TCP3从节点file目录权限BIND进程无写权限4serial是否递增改了记录没改serial5主从时间偏差时间差过大导致判断异常6日志报错看named日志具体原因这个顺序的逻辑是:先查权限和网络这些外部因素,再查配置和协议层面的因素,最后看日志兜底。实际排查中,前两步能解决大部分问题。注意:修改主节点记录后,一定要记得递增serial。我见过太多次"改了记录从节点没同步",最后发现就是serial没动。养成改完就改serial的习惯,能省下大量排查时间。5. 客户端接入与解析验证的完整链路5.1 客户端怎么指向内网DNS客户端接入有两种方式。一种是手动改/etc/resolv.conf,把主从两个IP都写上:nameserver 10.10.0.1 nameserver 10.10.0.2另一种是通过DHCP下发,适合机器多的场景。不管哪种方式,主从两个IP都要配,这样主节点挂了客户端会自动切到从节点。resolv.conf的查询顺序是从上到下,第一个不通才用第二个,所以主节点放前面。需要提醒的是,很多发行版的/etc/resolv.conf会被网络管理工具覆盖。如果你手动改了发现重启后失效,要去检查NetworkManager或systemd-resolved的配置,从源头改。5.2 用dig验证解析链路客户端配好后,用dig验证。先查内网域名:dig web.internal.example.lan再查公网域名,验证forwarders是否生效:dig www.example.com两个都返回正常结果,说明整条链路是通的。如果内网域名能解析但公网不行,检查forwarders配置;如果都不行,检查客户端到DNS服务器的网络连通性。还可以用dig +trace看解析的完整路径,不过内网场景下这个命令用处不大,因为内网域名不会走根服务器。更实用的是dig +short只看结果,脚本里常用。5.3 主从切换的实测验证高可用最直接的方法就是手动停掉主节点,看客户端是否还能正常解析。操作如下:# 在主节点上 systemctl stop named # 在客户端上 dig web.internal.example.lan如果客户端仍然返回正确结果,说明已经切到从节点。这时候再查从节点的日志,能看到它接管了查询请求。恢复主节点后,从节点会继续定期检查serial,保持同步。这个测试建议在正式上线前做一次,确认切换逻辑符合预期。有些环境因为客户端只配了一个DNS地址,主节点一停就全挂了,这种问题只有实测才能发现。6. 那些文档里不会写的踩坑经验6.1 serial忘记递增引发的"灵异事件"这是我最想强调的一个坑。主节点改了记录,dig @主节点能查到新记录,但dig @从节点还是旧记录,而且等多久都不更新。新手这时候容易怀疑网络、怀疑配置,其实原因就是serial没改。BIND判断是否需要同步,唯一依据就是serial。serial不变,从节点就认为数据没变化,不会触发传送。所以每次修改区域文件,第一件事就是改serial。我现在的习惯是改记录前先改serial,形成肌肉记忆。6.2 区域文件里的点号陷阱区域文件里,域名末尾的点号表示"完全限定域名"。带点和不带点,BIND的理解完全不同。比如:web IN A 10.10.0.10这里web不带点,BIND会自动补上当前区域的域名,变成web.internal.example.lan。而如果你写:web.internal.example.lan IN A 10.10.0.10不带末尾的点,BIND会再补一次区域名,变成web.internal.example.lan.internal.example.lan,这就错了。所以写完整域名时一定要带末尾的点,写相对名时不要带。这个规则记牢,能避免大量解析异常。6.3 日志级别与排查效率BIND默认的日志级别比较保守,出问题时信息不够。可以在配置里加一段logging,把查询日志和区域传送日志打开:logging { channel default_log { file "/var/log/named/named.log" versions 3 size 20m; severity info; print-time yes; }; category default { default_log; }; category xfer-out { default_log; }; category xfer-in { default_log; }; };xfer-out和xfer-in分别对应区域传送的发出和接收,排查同步问题时这两个category的日志最有价值。日志文件目录要确保BIND可写,否则日志打不出来。6.4 内网DNS的安全边界内网DNS虽然在内网,但安全配置不能省。几个关键点:allow-query限制查询来源,别写成any;allow-transfer只允许从节点,防止区域数据被随意拉取;recursion如果不需要对外提供递归,可以关掉或者限制来源。这些配置在options里都能控制。另外,BIND的版本要及时更新。老版本可能存在已知问题,内网环境虽然相对封闭,但保持更新是基本习惯。7. 后续可以怎么扩展这套架构主从模式跑通之后,这套架构还有不少可以延伸的方向。比如增加第二个从节点,进一步提升冗余,配置方式和第一个从节点完全一样,只要在主节点的allow-transfer里加上它的IP即可。再比如引入TSIG密钥,让区域传送带认证,安全性更高,适合对安全要求更严的环境。如果内网规模继续扩大,可以考虑拆分多个区域,按业务线或环境划分,每个区域独立做主从,避免单区域文件过大。还可以结合配置管理工具,把区域文件的变更纳入版本控制,每次改动有记录、可回滚。我自己在实际维护中体会最深的一点是:内网DNS的稳定性,八成取决于规范,两成取决于技术。serial递增、点号规则、allow-transfer限制,这些看似琐碎的规范,才是长期不出问题的关键。技术方案本身不复杂,难的是每次都按规矩来。把这套主从架构搭起来只是开始,真正让它稳定服务,靠的是日常的规范操作和定期检查。
1. 为什么内网自建DNS比你想的更值得折腾很多团队在规模小的时候,习惯直接用路由器或者运营商下发的DNS,机器少、访问目标单一,确实感觉不出问题。可一旦内网设备超过二三十台,或者开始有微服务、容器、测试环境、预发布环境这些需要靠域名互相寻址的场景,靠hosts文件和IP直连就会迅速变成一场灾难。改一台机器的hosts要登录一次,换一个IP要通知一圈人,测试环境域名和线上冲突更是家常便饭。这时候,自建一套内网DNS几乎是绕不开的选择。在Linux上做内网DNS,BIND(Berkeley Internet Name Domain)是最经典也最稳的方案。它足够老,老到几乎所有Linux发行版都自带或者一条命令就能装;它也足够强,强到全球根域名体系里相当一部分环节都在跑它。对于内网场景,BIND提供的主从(Master/Slave)复制能力尤其关键——主节点负责写记录,从节点自动同步,主节点挂了从节点还能继续提供解析,这就是内网DNS高可用的最低成本实现。这篇内容面向的是有一定Linux基础、想在内网快速搭起一套可用DNS主从架构的运维或开发人员。我会从BIND的安装、主从配置、区域文件编写、同步验证,一路讲到实际踩过的坑和排查思路。整套流程在几台普通Linux机器上就能复现,不需要额外硬件,也不需要复杂的编排系统。读完你至少能做到:内网域名自己说了算,主从自动同步,出问题知道从哪查。需要先说明一点,本文所有示例中的IP段、域名、主机名都是虚构的占位符,你在实际部署时替换成自己环境的真实值即可。下面进入正题。2. 动手之前先把BIND主从的账算清楚2.1 主从模式到底解决了什么问题单台DNS服务器最大的问题是单点故障。一旦这台机器宕机、网络抖动或者BIND进程崩溃,整个内网所有依赖域名解析的服务都会跟着遭殃。你可能会说,那我配两个DNS地址不就行了?问题在于,如果两台DNS各自独立维护,记录不一致,客户端查询结果就会随机漂移,排查起来极其痛苦。主从模式的核心价值就在于:写入只发生在主节点,从节点通过区域传送(Zone Transfer)自动拉取全量记录。这样既保证了数据一致性,又实现了冗余。客户端配置里把主从两个IP都写上,主节点不可用时从节点顶上,解析不中断。从实现角度看,BIND的主从同步依赖的是SOA记录中的serial字段。从节点定期检查主节点的serial,一旦发现主节点的serial比自己大,就触发一次区域传送。这个机制简单但有效,理解它是后面排查同步问题的关键。2.2 部署前需要确认的几件事在真正敲命令之前,有几项准备工作必须先确认,否则后面会反复返工。第一是网络规划。你需要明确主从两台机器的IP、内网要使用的域名后缀(比如internal.example.lan这种虚构后缀)、以及客户端会用哪些网段。域名后缀建议不要用公网真实存在的顶级域,避免解析时产生歧义。第二是端口和防火墙。DNS标准端口是53,TCP和UDP都要放行。主从之间还需要允许TCP 53用于区域传送。很多同步失败最后查出来都是防火墙只放了UDP没放TCP。第三是时间同步。主从机器的系统时间如果偏差太大,日志时间戳会对不上,排查问题时非常难受。建议部署前先确认两台机器时间基本一致。第四是SELinux和AppArmor。部分发行版默认开启的安全模块会阻止BIND绑定端口或读取区域文件,如果遇到莫名其妙的权限拒绝,先检查这里。下面这张表把关键准备项列清楚,方便对照检查:准备项主节点从节点说明静态IP需要需要避免DHCP导致地址漂移53端口TCP/UDP放行放行区域传送依赖TCP 53时间同步建议建议日志排查更顺畅安全模块确认放行确认放行避免权限拒绝域名后缀统一规划统一规划主从必须一致2.3 安装BIND:不同发行版的差异BIND在不同发行版上的包名和配置文件路径略有差异,这是新手最容易困惑的地方。我把它整理成一张对照表:发行版系安装命令主配置路径区域文件目录Debian/Ubuntuapt install bind9/etc/bind/named.conf/etc/bind/RHEL/CentOSyum install bind/etc/named.conf/var/named/通用源码编译安装自定义自定义以Debian系为例,安装完成后BIND会自动注册为系统服务,服务名通常是bind9或named。安装后先别急着改配置,用named -v确认版本,用systemctl status看服务状态,确保基础环境是干净的。提示:如果你的发行版默认装了systemd-resolved并占用了53端口,BIND会启动失败。这种情况需要先停用或调整该服务,把53端口让出来。3. 主节点配置:从named.conf到区域文件3.1 主配置文件的整体结构BIND的主配置文件通常由三部分组成:全局选项(options)、日志配置(logging)、区域声明(zone)。对于内网场景,我们重点关注options和zone两块。一个精简但完整的主节点配置大致长这样(以虚构域名internal.example.lan为例):options { listen-on port 53 { 127.0.0.1; 10.10.0.1; }; listen-on-v6 { none; }; directory "/var/named"; allow-query { 10.10.0.0/24; 127.0.0.1; }; allow-transfer { 10.10.0.2; }; recursion yes; forwarders { 8.8.8.8; }; }; zone "internal.example.lan" IN { type master; file "internal.example.lan.zone"; allow-update { none; }; };这里有几个参数值得展开说。listen-on指定BIND监听的地址,内网场景建议只监听内网IP和本地回环,不要监听any,减少暴露面。allow-query限制哪些网段可以查询,防止被当成开放解析器滥用。allow-transfer是主从同步的关键,只允许从节点IP发起区域传送,这是安全底线。forwarders的作用是:当查询的域名不在本地区域内时,转发给上游DNS。内网场景下这个配置让BIND既能解析内网域名,又能解析公网域名,一举两得。3.2 区域文件怎么写才不出错区域文件是真正存放记录的地方,格式上最容易出错。一个标准的正向区域文件包含SOA、NS、A、CNAME、MX等记录类型。下面是一个可用的示例:$TTL 3600 @ IN SOA ns1.internal.example.lan. admin.internal.example.lan. ( 2024010101 ; serial 3600 ; refresh 1800 ; retry 604800 ; expire 86400 ; minimum ) @ IN NS ns1.internal.example.lan. @ IN NS ns2.internal.example.lan. ns1 IN A 10.10.0.1 ns2 IN A 10.10.0.2 web IN A 10.10.0.10 db IN A 10.10.0.11 cache IN CNAME web.internal.example.lan.这里有几个细节必须强调。serial字段是主从同步的触发器,每次修改记录后必须手动递增,否则从节点不会同步。建议用日期加序号的方式,比如2024010101表示2024年1月1日第1次修改,这样既直观又不容易重复。SOA记录末尾的域名必须带点,admin.internal.example.lan.最后那个点表示这是完全限定域名,漏掉点会导致解析异常。同理,NS记录里的域名也要带点。这是新手最常踩的坑之一。CNAME记录不能和其他记录共存。比如你不能给cache同时配CNAME和A记录,这是DNS协议层面的限制,不是BIND的问题。3.3 配置检查与启动改完配置别急着重启服务,先用BIND自带的检查工具验证语法:named-checkconf /etc/named.conf named-checkzone internal.example.lan /var/named/internal.example.lan.zonenamed-checkconf检查主配置语法,named-checkzone检查区域文件语法。两个命令都通过后再重启服务:systemctl restart named systemctl status named服务起来后,用dig或nslookup在本地验证:dig @127.0.0.1 web.internal.example.lan如果返回正确的A记录,说明主节点基本可用。如果返回SERVFAIL或REFUSED,先看日志/var/log/messages或journalctl -u named,日志里通常有明确原因。4. 从节点配置:让同步真正跑起来4.1 从节点的zone声明与主节点不同从节点的配置结构和主节点类似,但zone部分的type要改成slave,并且要指定masters指向主节点:zone "internal.example.lan" IN { type slave; file "slaves/internal.example.lan.zone"; masters { 10.10.0.1; }; };注意file的路径。从节点的区域文件是自动生成的,不需要你手动创建,BIND从主节点拉取后会自动写入这个路径。所以这个目录必须对BIND进程可写,否则同步会失败。Debian系默认在/var/cache/bind/,RHEL系在/var/named/slaves/,具体以你的配置为准。从节点的options里,allow-transfer可以设为none,因为从节点不需要再向别人传送。allow-query则要和主节点保持一致,保证客户端能正常查询。4.2 区域传送的触发与验证从节点启动后,会主动向主节点发起一次区域传送。触发条件是:从节点本地没有区域文件,或者主节点的serial比本地大。传送成功后,从节点会在指定路径生成区域文件。验证同步是否成功,有几个层次的方法。最直接的是看从节点上区域文件是否生成:ls -l /var/named/slaves/如果文件存在且大小不为零,说明至少传送过一次。再进一步,用dig直接查从节点:dig @10.10.0.2 web.internal.example.lan返回和主节点一致的结果,说明从节点已经在正常提供服务。还可以在主节点上主动触发一次传送来测试:dig @10.10.0.1 internal.example.lan AXFR这个命令会列出整个区域的所有记录。如果返回完整记录列表,说明区域传送通道是通的。如果返回Transfer failed,就要去查allow-transfer配置和防火墙。4.3 同步失败时按这个顺序排查主从同步失败是内网DNS最常见的故障,我把它整理成一个排查顺序,照着走基本能定位:排查步骤检查内容常见问题1主节点allow-transfer从节点IP没加进去2防火墙TCP 53只放了UDP没放TCP3从节点file目录权限BIND进程无写权限4serial是否递增改了记录没改serial5主从时间偏差时间差过大导致判断异常6日志报错看named日志具体原因这个顺序的逻辑是:先查权限和网络这些外部因素,再查配置和协议层面的因素,最后看日志兜底。实际排查中,前两步能解决大部分问题。注意:修改主节点记录后,一定要记得递增serial。我见过太多次"改了记录从节点没同步",最后发现就是serial没动。养成改完就改serial的习惯,能省下大量排查时间。5. 客户端接入与解析验证的完整链路5.1 客户端怎么指向内网DNS客户端接入有两种方式。一种是手动改/etc/resolv.conf,把主从两个IP都写上:nameserver 10.10.0.1 nameserver 10.10.0.2另一种是通过DHCP下发,适合机器多的场景。不管哪种方式,主从两个IP都要配,这样主节点挂了客户端会自动切到从节点。resolv.conf的查询顺序是从上到下,第一个不通才用第二个,所以主节点放前面。需要提醒的是,很多发行版的/etc/resolv.conf会被网络管理工具覆盖。如果你手动改了发现重启后失效,要去检查NetworkManager或systemd-resolved的配置,从源头改。5.2 用dig验证解析链路客户端配好后,用dig验证。先查内网域名:dig web.internal.example.lan再查公网域名,验证forwarders是否生效:dig www.example.com两个都返回正常结果,说明整条链路是通的。如果内网域名能解析但公网不行,检查forwarders配置;如果都不行,检查客户端到DNS服务器的网络连通性。还可以用dig +trace看解析的完整路径,不过内网场景下这个命令用处不大,因为内网域名不会走根服务器。更实用的是dig +short只看结果,脚本里常用。5.3 主从切换的实测验证高可用最直接的方法就是手动停掉主节点,看客户端是否还能正常解析。操作如下:# 在主节点上 systemctl stop named # 在客户端上 dig web.internal.example.lan如果客户端仍然返回正确结果,说明已经切到从节点。这时候再查从节点的日志,能看到它接管了查询请求。恢复主节点后,从节点会继续定期检查serial,保持同步。这个测试建议在正式上线前做一次,确认切换逻辑符合预期。有些环境因为客户端只配了一个DNS地址,主节点一停就全挂了,这种问题只有实测才能发现。6. 那些文档里不会写的踩坑经验6.1 serial忘记递增引发的"灵异事件"这是我最想强调的一个坑。主节点改了记录,dig @主节点能查到新记录,但dig @从节点还是旧记录,而且等多久都不更新。新手这时候容易怀疑网络、怀疑配置,其实原因就是serial没改。BIND判断是否需要同步,唯一依据就是serial。serial不变,从节点就认为数据没变化,不会触发传送。所以每次修改区域文件,第一件事就是改serial。我现在的习惯是改记录前先改serial,形成肌肉记忆。6.2 区域文件里的点号陷阱区域文件里,域名末尾的点号表示"完全限定域名"。带点和不带点,BIND的理解完全不同。比如:web IN A 10.10.0.10这里web不带点,BIND会自动补上当前区域的域名,变成web.internal.example.lan。而如果你写:web.internal.example.lan IN A 10.10.0.10不带末尾的点,BIND会再补一次区域名,变成web.internal.example.lan.internal.example.lan,这就错了。所以写完整域名时一定要带末尾的点,写相对名时不要带。这个规则记牢,能避免大量解析异常。6.3 日志级别与排查效率BIND默认的日志级别比较保守,出问题时信息不够。可以在配置里加一段logging,把查询日志和区域传送日志打开:logging { channel default_log { file "/var/log/named/named.log" versions 3 size 20m; severity info; print-time yes; }; category default { default_log; }; category xfer-out { default_log; }; category xfer-in { default_log; }; };xfer-out和xfer-in分别对应区域传送的发出和接收,排查同步问题时这两个category的日志最有价值。日志文件目录要确保BIND可写,否则日志打不出来。6.4 内网DNS的安全边界内网DNS虽然在内网,但安全配置不能省。几个关键点:allow-query限制查询来源,别写成any;allow-transfer只允许从节点,防止区域数据被随意拉取;recursion如果不需要对外提供递归,可以关掉或者限制来源。这些配置在options里都能控制。另外,BIND的版本要及时更新。老版本可能存在已知问题,内网环境虽然相对封闭,但保持更新是基本习惯。7. 后续可以怎么扩展这套架构主从模式跑通之后,这套架构还有不少可以延伸的方向。比如增加第二个从节点,进一步提升冗余,配置方式和第一个从节点完全一样,只要在主节点的allow-transfer里加上它的IP即可。再比如引入TSIG密钥,让区域传送带认证,安全性更高,适合对安全要求更严的环境。如果内网规模继续扩大,可以考虑拆分多个区域,按业务线或环境划分,每个区域独立做主从,避免单区域文件过大。还可以结合配置管理工具,把区域文件的变更纳入版本控制,每次改动有记录、可回滚。我自己在实际维护中体会最深的一点是:内网DNS的稳定性,八成取决于规范,两成取决于技术。serial递增、点号规则、allow-transfer限制,这些看似琐碎的规范,才是长期不出问题的关键。技术方案本身不复杂,难的是每次都按规矩来。把这套主从架构搭起来只是开始,真正让它稳定服务,靠的是日常的规范操作和定期检查。