平时做运维的朋友肯定都有过这种经历公司内部新起了一套系统IP地址越来越多今天要连这个、明天要连那个总不能天天翻Excel表格。更尴尬的是内网服务想用一个好记的域名访问结果发现公共DNS根本不认识你的内网地址。这个时候在自己服务器上搭一个DNS正向解析服务就成了最靠谱的解法。这篇文章要聊的就是在CentOS 7.6上从零开始把DNS正向解析应用服务完整地搭起来让它真正能干活、能上线、能扛住日常使用。我先把话放前面这篇文章适合谁看Linux运维、系统管理员、对网络服务有好奇心的开发甚至只是想把家里/实验室的服务器整理出个“门牌号”的朋友都能在这里面找到能直接抄作业的命令和思路。我会把配置DNS服务涉及的核心文件、参数、调试方法、排障过程全部拆开讲尽量把每一步背后的“为什么”也说出来而不是丢给你一串命令让你瞎敲。1. 内容整体设计与思路拆解1.1 DNS正向解析到底在解决什么问题DNS的全称是Domain Name System中文叫域名系统。你在浏览器里输入一个网址DNS负责把这个“人类友好的名字”翻译成“机器认识的IP地址”。这个动作就叫解析。其中“正向解析”指的是给你一个域名返回对应的IP地址。反向解析则反过来给你IP找域名。用一个生活化的类比DNS就像手机通讯录。你给朋友打电话不需要记住他的手机号只需要在通讯录里点名字就能拨出去。正向解析就是这个“查名字找号码”的过程。企业内部也一样如果没有自己的DNS访问某台服务器就只能是ssh 192.168.1.25这种干巴巴的IP一旦记错或者IP调整全是麻烦。有了DNS之后你只需要ssh helpdesk.example.com剩下的交给DNS去查表。这篇文章里要做的事情本质上就是用一台CentOS 7.6服务器创建一个“内部通讯录”让内网所有机器通过它来找到彼此。而且这个通讯录要支持增删改查——新加一台服务器改一条记录就能生效不需要去动任何客户端的配置。1.2 为什么要自建DNS而不直接用公共DNS有人会问现在云上的公共DNS又快又稳直接用它不行吗这个问题的答案就是自建DNS的核心价值所在。公共DNS解析的是公网域名比如百度、谷歌这些。但企业内部有着大量私网IP比如192.168.x.x、10.x.x.x这些网段这些地址在公共DNS的数据库里根本不存在。就算你在公网买了一个域名想要把server1.example.com映射到内网IP公共DNS也不允许你随意修改解析记录因为域名并不归你托管。所以自建DNS真正的用途是把这个企业内部的域名空间管理起来让内网客户端能解析到内网服务。与此同时它还能兼职做“转发代理”——对于自己不知道的公网域名它可以去问上一级DNS服务器比如运营商的DNS拿到答案后返回给客户端。这种模式既解决了内网域名解析又不妨碍员工正常访问互联网一举两得。1.3 选择BIND方案而不是其他工具CentOS 7.6上最正统、最常见、资料最多的DNS服务程序是BINDBerkeley Internet Name Domain。安装的包名通常是bind对应的系统服务叫named。BIND稳重、成熟、文档丰富而且CentOS自带仓库里就能安装不需要额外折腾第三方源这对生产环境来说非常重要。我见过有人推荐用dnsmasq或者unbound来替代它们确实更轻量配置更简单。但如果你有强烈的正向解析需求、后续可能还要做多级域名、子域授权、视图解析等功能BIND的扩展性明显更好。可以说BIND是“下限不低、上限极高”的全能选手。尤其是对新手网上一搜全是BIND的资料踩坑了也能找到对应的解决方案。本文的核心操作就围绕BIND展开。2. 环境规划与安装准备2.1 安装前的环境要求先说一下我这次实操的环境基础项目配置操作系统CentOS 7.6 x86_64服务器IP192.168.10.88主机名ns1.example.com待解析域名example.comDNS服务BIND 9.x系统自带客户端同网段内一台CentOS 7测试用在正式安装之前有三件事需要处理好很多人装完就卡在这些地方第一件事是关闭或放行SELinux。CentOS默认开启SELinux而DNS服务在这种强制访问控制环境下偶尔会出奇怪的问题最常见的是named进程无法读取配置文件或写日志。生产环境如果你有成熟的SELinux策略可以保留但如果只是一个内网测试环境最简单粗暴的方法是先检查状态必要时临时关闭。# 查看SELinux状态 getenforce # 临时关闭重启失效 setenforce 0 # 永久关闭需修改 /etc/selinux/config 里的 SELINUXdisabled第二件事是放行防火墙的53端口。DNS服务默认监听UDP/TCP 53端口额外地TCP 53端口用于区域传输。内网如果开着防火墙不放行谁也连不上你。firewall-cmd --permanent --add-port53/udp firewall-cmd --permanent --add-port53/tcp firewall-cmd --reload如果用的是iptables也要自己加规则。建议先确认防火墙状态systemctl status firewalld第三件事是规划好静态IP。DNS服务器最忌讳IP变化一旦IP变了所有指向它的客户端就全废了。所以务必把服务器IP设置成静态设置好主机名确保网络通畅。2.2 安装BIND主程序安装过程很简单一条命令搞定yum install -y bind bind-utilsbind是服务端主程序bind-utils里面包含了dig和nslookup这些客户端测试工具调试DNS时几乎是必备。装完之后验证一下版本named -v如果能看到版本号输出比如BIND 9.11.4-P2 (Extended Support Version)那就说明安装成功。安装完之后建议先看一下软件都装了哪些关键路径知道每个文件干什么。BIND的目录结构是/etc/named.conf # 主配置文件 /etc/named.rfc1912.zones # 区域声明的辅助文件默认包含 /var/named/ # 区域数据文件默认目录 /var/named/named.localhost # 本地正向区域示例 /var/named/named.empty # 空区域示例 /var/named/slaves/ # 从服务器区域存放目录 /var/named/data/ # 统计和缓存数据/etc/named.conf是总控制台/var/named/下的zone文件是真正的“解析账本”。主配置告诉你“这台DNS服务器怎么运行”zone文件告诉你“每个域名的记录长什么样”两者缺一不可。3. 核心配置修改与正向解析区域文件3.1 修改named.conf主配置文件先备份原配置这是个好习惯。我一般不管原文件多长先把它挪走或复制一份再说cp /etc/named.conf /etc/named.conf.bak然后编辑主配置文件。CentOS自带的/etc/named.conf内容比较多注释也多。对于纯粹的正向解析场景我建议直接写一个干净的最小配置便于理解和排障。下面是我在实操中用的完整版vi /etc/named.confoptions { listen-on port 53 { 192.168.10.88; 127.0.0.1; }; 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; allow-query { any; }; recursion yes; forwarders { 114.114.114.114; 8.8.8.8; }; dnssec-enable no; dnssec-validation no; }; logging { channel default_debug { file data/named.run; severity dynamic; }; }; zone . IN { type hint; file named.ca; }; include /etc/named.rfc1912.zones;我逐项解释一下关键参数的意思这比照着敲更重要listen-on指定程序监听的IP和端口。原先默认注释掉时只监听localhost其他机器根本访问不了。这里我写了服务器本身的内网IP和回环地址。allow-query允许谁来查询。测试环境直接用any生产环境你可以限定为一个网段比如192.168.10.0/24。recursion yes开启递归查询。客户端只需要向它发起一次查询它会帮客户端跑完整个查询流程再返回最终答案。这是绝大多数内网DNS的使用方式。forwarders开启转发功能。遇到本机不知道的公网域名就往这个列表里的DNS去问。这里我写了公共的DNS地址内网环境按运营商分配的来写就行。dnssec-enable no和dnssec-validation no关闭DNSSEC校验。这一步在早期版本中尤其重要因为如果上游DNS服务器不支持DNSSEC或配置不完整校验失败会导致解析异常。测试环境或者内网环境直接关掉最省心。zone . IN { type hint; file named.ca; }这是根域级的“hint”配置指向根域服务器列表用于递归解析公网域名时“找根”所用一般不需要改动。改完主配置后启动服务时报错的很大一部分原因就出在语法上。BIND提供了检查工具named-checkconf /etc/named.conf这个命令没有输出就代表语法没问题有输出会直接指出第几行报错。3.2 声明正向解析的zone区域主配置只是定义了服务器的通用行为要让DNS真正知道“example.com这个域归我管”还需要在区域配置文件里声明。你可以直接在/etc/named.conf的末尾加也可以像我一样把区域声明写在/etc/named.rfc1912.zones这个已include的文件里。两种方式效果一样我个人习惯写在named.rfc1912.zones中因为这个文件本身就是专门放自定义zone的结构清晰也容易通过rndc reload单独加载。打开文件vi /etc/named.rfc1912.zones在末尾追加zone example.com IN { type master; file example.com.zone; allow-update { none; }; };这段配置的含义是我这个服务器是example.com这个域的主DNS服务器type master区域数据存放在/var/named/example.com.zone文件里不允许动态更新allow-update none。allow-update none非常重要。如果开启了动态更新又不加限制任何主机都可以随意篡改你的DNS记录这是极其危险的。对于静态区域永远保持none开启状态是最稳妥的。再用工具检查一下named-checkconf /etc/named.rfc1912.zones注意/etc/named.conf末尾已经include了这个文件所以实际上重新检查named.conf即可。3.3 配置正向解析区域数据文件声明好zone之后必须创建对应的区域数据文件否则服务启动会报错。这个文件的全路径是/var/named/example.com.zone文件名要与上面file字段指定的完全一致。vi /var/named/example.com.zone我写的示例内容如下$TTL 86400 $ORIGIN example.com. IN SOA ns1.example.com. root.example.com. ( 2024071501 ; serial 3600 ; refresh 900 ; retry 604800 ; expire 86400 ; minimum ) IN NS ns1.example.com. IN MX 10 mail.example.com. ns1 IN A 192.168.10.88 www IN A 192.168.10.10 mail IN A 192.168.10.20 ftp IN CNAME www这个文件是DNS正向解析的核心我拆解开讲。第一行$TTL 86400规定了默认的生存时间单位是秒。86400秒等于24小时。客户端解析完毕后会把结果缓存这么久你觉得记录可能要改就把TTL调小比如600秒10分钟生效等稳定了再调大。$ORIGIN example.com.定义了默认的追加后缀。注意这里的写法zone文件里的域名末尾都有个点代表全称的终止符。后面凡是没写点的域名都会被自动补上example.com.这个后缀。比如www IN A 192.168.10.10实际表达的就是www.example.com.。SOA记录是Start of Authority的缩写它表达的是“这个域的管理信息”。这里有5个数字参数serial序列号从服务器判断区域文件是否更新就靠它。每次修改区域文件这个值必须递增。一旦你觉得改完配置不生效优先怀疑serial没有递增。refresh从服务器刷新主服务器数据的时间间隔。retry刷新失败后重试的时间间隔。expire从服务器一直无法联系主服务器过多久放弃权威。minimum负缓存TTL。NS记录声明了这个域是由哪个域名服务器负责的这里是ns1.example.com.。MX记录是邮件交换记录10是优先级数字越小越优先。这里表示example.com的邮件服务器是mail.example.com优先级10。A记录是真正的正向解析记录域名到IPv4的映射。这里我写了三条ns1指向192.168.10.88也就是DNS服务器自己。www指向192.168.10.10假设是一台Web服务器。mail指向192.168.10.20假设是邮件服务器。CNAME是别名记录我写的是ftp IN CNAME www表示ftp.example.com是www.example.com的别名解析时会把www.example.com的IP返回。真实业务中你还会用到AAAA记录IPv6地址映射、TXT记录文本验证、SPF邮件认证用等但内网正向解析最常用的就是A、CNAME、MX这三种。文件创建完成后一定要用工具检查语法。以我上面的配置为例执行named-checkzone example.com /var/named/example.com.zone输出OK就表示检查通过。如果出现报错比如末尾没加“.”、忘记写$ORIGIN之类的工具会明确告诉你哪一行有问题。3.4 启动服务并加入开机自启配置都改好了、检查也都通过了就可以正式启动服务了systemctl start named systemctl enable named启动之后看状态systemctl status named如果一切正常你会看到active (running)。查看端口监听情况ss -lntup | grep named正常情况下53端口应该同时监听TCP和UDP而且监听IP包含内网地址。到这里服务端配置就完成了。接下来进入客户端验证环节。4. 启动测试与客户端验证4.1 客户端配置DNS指向服务端跑起来了客户端得知道用这个DNS服务。修改客户端机器上的DNS配置文件vi /etc/resolv.conf把nameserver改成DNS服务器地址nameserver 192.168.10.88如果这个客户端是静态IP配置的还可以直接改网卡配置文件里DNS1参数或者用DHCP方式的客户端直接改/etc/resolv.conf即可。改完建议确认一下cat /etc/resolv.conf4.2 用nslookup验证正向解析结果改完DNS指向第一时间用nslookup验证。nslookup www.example.com如果配置全部正确会看到类似这样的结果Server: 192.168.10.88 Address: 192.168.10.88#53 Name: www.example.com Address: 192.168.10.10这说明客户端向192.168.10.88的53端口发起了查询成功拿到了www.example.com对应的IP地址。再验证一下mx和nsnslookup -querymx example.com nslookup -queryns example.com4.3 用dig工具深入测试dig工具更强大建议优先使用它来做深度排查。基础测试dig www.example.com输出信息更丰富可以重点关注几个部分status: NOERROR表示查询成功。ANSWER SECTION是权威答案部分会列出www.example.com.对应的A记录。QUESTION SECTION是问题部分告诉你查的是什么。用dig还可以指定特定的记录类型dig www.example.com A dig example.com MX dig example.com NS还有一种值得一提的测试方式就是直接在dig后面指定服务器不依赖/etc/resolv.conf里的nameserverdig 192.168.10.88 www.example.com这在多台DNS服务器并存、需要对比验证不同服务器答案时非常有用。4.4 ping命令做最后的连通性验证DNS解析最终是为了连通。用一条命令验证ping -c 4 www.example.com如果显示www.example.com (192.168.10.10)并能正常收到回包说明DNS正向解析服务端、客户端配置、网络连通全部OK。我每次改完配置都习惯做三连验证第一步named-checkcheckzone检查文件语法第二步systemctl restart named重启服务第三步dig直接验证解析结果。不要改完记录不检查就直接上线我吃过这个亏。4.5 修改解析记录后的生效策略日常使用中你会频繁修改区域文件来新增、调整解析记录。这种情况下有一个重要的操作习惯修改/var/named/example.com.zone文件后需要先递增SOA记录中的serial号再执行语法检查然后使用rndc reload重载配置或者systemctl restart named。建议用rndc reload替代restart。restart会把服务整个重启而reload只是重新加载配置文件影响范围更小也不会导致当时正在进行的查询被强制中断。如果只是新增了一条A记录用reload就够了。rndc reload顺便提一下named进程启动时运行身份是named用户所以/var/named/下的zone文件如果是手动创建它的属主一般是root需要确保named用户至少能读。最常见的权限问题之一是root创建的zone文件缺少读权限导致服务加载不了区域文件对应的现象是客户端查询返回SERVFAIL。建议把域文件的属主改成named用户或者加上可读权限。5. 常见问题与排查技巧实录5.1 named-checkconf和named-checkzone都通过了但服务起不来即使两个检查工具都通过服务仍然可能启动失败。最常见的原因是权限问题。报错日志里如果看到open: /var/named/example.com.zone: permission denied说明named进程没有该文件的读权限。解决办法chown named:named /var/named/example.com.zone chmod 640 /var/named/example.com.zone注意/var/named目录下有些文件是root的如果设置了过于严格的SELinux文件标签也可能导致类似情况。建议先检查日志journalctl -u named -f tail -f /var/log/messages5.2 客户端dig查询返回REFUSEDREFUSED通常意味着服务器收到了请求但allow-query配置不允许这个来源查询。我在早期配置时碰到过一次原因就是allow-query设成了{ 127.0.0.1; }导致其他机器查询全部被拒绝。解决办法是把allow-query改为any或者内网网段allow-query { 192.168.10.0/24; };5.3 防火墙和SELinux导致的网络不通客户端dig的时候出现超时connection timed out; no servers could be reached非常大概率是防火墙挡住了53端口。确认放行firewall-cmd --list-all如果确实没放行按前面的命令补上即可。SELinux方面如果你的环境开启了SELinux又不愿意完全关闭可以单独放行named服务需要的网络权限setsebool -P named_write_master_zones 1这条布尔值设置允许named进程写主区域文件有时候开发测试模式下很有用。生产环境还是要按最小权限原则来做。5.4 修改了zone文件客户端还是拿到旧IP这是一个非常高频的坑。最大的可能就是你忘了递增serial号。BIND比较serial值如果发现没有变大就不会重新加载区域数据。第二个可能是TTL太长客户端的本地缓存里还留着旧的解析结果。解决办法是临时把TTL调小比如600秒等应用端缓存都过期了再改回来。第三个可能是改完文件之后用的是systemctl restart named而不是rndc reload并且重启之前没有做named-checkzone检查结果文件在语法上就错了服务起来立刻又崩溃。我在压力状态下犯过这种错误记得改完什么都先检查再说。5.5 查询公网域名失败但内网域名正常这种情况基本可以锁定在forwarders和recursion配置上。先确认recursion yes;确实没有注释。再确认forwarders填写正确比如填了114.114.114.114但服务器本身的网络根本访问不了这个公共DNS。可以用curl或者telnet快速测一下telnet 114.114.114.114 53如果连接不上说明上游DNS地址不可达换一个运营商提供的DNS地址再试。还有一点容易被忽略/etc/named.conf里dnssec-enable no; dnssec-validation no;没有加。如果上游DNS开启了DNSSEC但你的BIND有校验逻辑查询可能会因为签名不完整被拒掉结果同样是公网解析失败。既然你自建DNS主要是为了内网把这个校验关掉最省事。5.6 常见问题速查表现象常见原因排查/解决要点服务启动失败zone文件权限、语法错误查看journalctl -u named日志named-checkzone检查语法客户端超时防火墙未放行53端口、IP配错firewall-cmd --list-all客户端cat /etc/resolv.conf查询返回REFUSEDallow-query限制过严改为any或内网网段查询返回SERVFAILzone文件加载失败、权限问题检查/var/named目录权限、named用户读权限改配置后不生效serial没递增、TTL缓存、没reload递增serial调小TTLrndc reload公网域名解析失败forwarders不可达、recursion被注释换可用的上游DNS确认recursion yes6. 生产环境落地的额外建议上面这套流程基本覆盖了CentOS 7.6上搭建DNS正向解析服务的全部核心结点。但如果这个DNS服务是要真正放到生产环境里的我还有几条实际操作中总结出来的经验要和你说。第一DNS服务器一定要设置静态IP不要用DHCP。我见过因为IP被DHCP重新分配到别的机器上导致全公司网络解析瘫痪的场面。给DNS服务器床一个永久的“固定工位”是所有后续配置的地基。第二生产环境的DNS操作要留下痕迹。改zone文件之前先备份cp /var/named/example.com.zone /var/named/example.com.zone.$(date %F)万一哪次手滑删错了一行还能秒级回滚。第三有条件的话建议配置一台备用DNS服务器用区域传输的方式从主DNS同步数据。这样主服务器宕机了客户端还能用备用服务器的DNS继续解析不会造成大范围故障。本文不展开从服务器的细节但思路要先建立起来。第四定期检查DNS查询日志和统计信息。BIND默认会通过logging配置记录运行日志用rndc stats还可以查看查询量的统计。在排查异常流量或者确认优化效果时这些数据都很有价值。我个人在实际操作里的体会是DNS服务一旦配置完成并稳定运行存在感极低但一旦出了问题就是全公司“断网”级别的大事。所以配置的时候慢一点、仔细一点每一步检查都做到位远比一开始图快、后面反复返工更划算。最后再分享一个小技巧每次改完zone文件记得敲一遍named-checkzone这一条命令只需要几秒钟却能帮你屏蔽掉大部分粗心造成的故障。后续如果你想继续深入可以试着加一条反向解析配置、做DNS视图按来源返回不同解析结果或者做主从同步把这些练通了你就是团队里最懂DNS的那个。