
做Linux运维和系统管理这行DNS服务器迟早要上手。不管你是管理几十台服务器的运维工程师还是想往系统架构方向走的技术人只要内网里有域名解析需求比如把gitlab.internal、nexus.local这类内部地址统一管理起来就绕不开自建DNS服务。这篇博文我要讲的就是Linux系统下DNS服务器的配置与管理从原理梳理到BIND安装、正向反向解析配置、排查方法整体走一遍照着操作就能搭出一台能用于内网生产环境的DNS服务器。这篇文章适合这几类人看刚学完Linux基础命令、想进入服务配置阶段的进阶者工作中需要维护内网域名解析但之前只会改/etc/hosts的运维新手还有想系统梳理BIND配置和调试方法的开发者。如果你已经能独立配置DHCP、Nginx这类服务但对DNS还停留在“只会在路由器里填两个IP”的水平那这篇内容正好补上这块短板。1. 做DNS服务前先把角色和原理盘明白1.1 DNS服务器在Linux运维中的定位很多刚接触Linux服务的人容易把DNS当成一个“装好就能用”的东西其实DNS服务是典型的“配置简单、排错复杂”的模块。它对外只开一个UDP/TCP 53端口但内部涉及区域文件、权限模型、递归策略、缓存机制、主从同步等多个环节任何一个环节出错表面现象都可能是“解析不了域名”。在企业内网里DNS服务器承担的角色通常比公网DNS更重。它不仅要解析内部主机名还要处理外部域名的递归查询同时承担一些安全策略比如限制某些域名的解析、记录客户端查询日志等。也就是说内网DNS不只是“域名翻译机”它实际上是网络流量的一个隐形入口。我在实际运维中有一个体会排查“电脑上不了网”的问题时十次有六次最终都会落到DNS头上。IP能通但域名解析失败这种情况几乎每天都在发生。所以在进阶Linux服务配置时先把DNS吃透性价比非常高。1.2 常见的三种部署角色缓存、权威、转发配置DNS服务器之前先要搞清楚你需要的到底是哪一种角色不同角色的配置差异很大。缓存DNS服务器是最常见的角色。它自己不保存任何权威数据收到客户端查询后会递归向上级DNS服务器获取结果然后缓存起来。内网客户端把DNS地址指向这台机器它就负责把公网域名解析出来同时利用缓存加速后续查询。这种部署最简单也最实用适合绝大多数网络环境。权威DNS服务器保存的是某个域名区域的权威数据比如你可以为example.internal这个内部域名指定A记录、MX记录、CNAME记录等。当其他DNS服务器或者客户端查询这个区域下的域名时这台机器会直接给出权威答案。内网私有域名的解析靠的就是这种角色。转发DNS服务器则是将收到的查询请求统一转发给固定的上游DNS服务器自己不直接走根域迭代。这种模式在出口统一管理的网络里很常见比如公司只有一条出口线路希望所有DNS请求都通过指定的运营商或内部DNS出去就用转发模式。搞清楚这三种角色再看配置文件就会豁然开朗。很多文章一上来就让你写zone结果你只想搭一个临时缓存DNS最后配置又复杂又容易错就是角色没对应上。1.3 选型思考为什么大多数场景默认BINDLinux下能提供DNS服务的软件不少著名的有BIND、dnsmasq、PowerDNS、Unbound等。但如果你去翻企业运维手册绝大多数还是BIND也就是named服务因为它是目前功能最完整、资料最多、兼容性最好的DNS实现。有人可能会问dnsmasq配置不是更简单吗确实dnsmasq在局域网里做DNS缓存和DHCP服务非常轻量两三行配置就能干活。但它的定位是轻量级工具做不了复杂的分区授权、视图view、细粒度ACL这些功能满足不了中大型内网的管控需求。BIND虽然配置上手门槛高一些但胜在稳定、可控、生态成熟像根服务器系统用的也是BIND衍生或同类技术。所以生产环境我建议直接从BIND入手后续不管是做主从同步、配置智能DNS还是做访问控制都有现成方案可抄。2. 在Linux上安装BIND并完成基础配置2.1 不同发行版的安装命令差异BIND在不同Linux发行版里的包名不太一样最容易踩坑的地方就在这里。CentOS、Rocky、AlmaLinux这类RPM系发行版服务名和包名都叫bind安装后的主程序是/usr/sbin/named服务管理用systemctl操作named。Debian、Ubuntu系列则拆得更细服务包叫bind9配置文件放在/etc/bind/下主配置文件是named.conf服务管理用systemctl操作bind9。# RPM系CentOS / Rocky / AlmaLinux / 银河麒麟 / 统信UOS sudo dnf install -y bind bind-utils # Debian系Ubuntu / Debian sudo apt update sudo apt install -y bind9 bind9utils bind9-doc顺带说一下国产系统现在很多单位在推进Linux国产化银河麒麟和统信UOS的服务器版本如果底层是RPM系安装方式和CentOS基本一致bind-utils这个工具包一定要装后面排查解析问题全靠它里面的dig、nslookup、host命令。2.2 认识主配置文件named.conf安装完BIND第一件事不是急着启动服务而是先看配置文件。RPM系发行版的主配置文件在/etc/named.conf里面默认会有一些基础配置但比较散。实际管理时我习惯把它拆成多个子配置文件然后通过include引入比如区域文件单独放一个目录。这样结构清晰后续加域名不用反复动主配置。named.conf最常见的几个配置块包括options、zone和acl。options定义全局参数比如监听地址、允许查询的网段、允许递归的网段、转发器等。zone定义具体的权威区域。acl定义访问控制列表方便在配置里复用IP网段。options { listen-on port 53 { 127.0.0.1; 192.168.1.53; }; 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 { localhost; 192.168.1.0/24; }; recursion yes; allow-recursion { localhost; 192.168.1.0/24; }; forwarders { 223.5.5.5; 119.29.29.29; }; dnssec-validation auto; managed-keys-directory /var/named/dynamic; pid-file /run/named/named.pid; };其中listen-on表示监听哪些IP地址上的DNS查询allow-query表示允许哪些客户端来查询recursion yes开启递归查询allow-recursion限定递归权限forwarders配置上游DNS转发地址。我在测试环境通常会配置223.5.5.5和119.29.29.29作为上游也就是国内常用的公共DNS速度快而且稳定性不错。2.3 第一个可用的缓存DNS服务器配置如果你的需求只是给内网提供域名解析缓存不需要维护内部域名那配置可以非常精简。关键就是recursion yes和forwarders。这种情况不需要写任何zoneBIND默认会走根服务器的迭代查询路径也可以直接交给上游DNS。我给新环境搭缓存DNS时通常会做这几步安装包、清掉默认不必要的zone配置、设定监听和allow-query、指定forwarders、启动服务、放防火墙。注意RPM系发行版自带的named.conf里已经定义了root zone和localhost zone这几个zone建议保留不要乱删删错了可能导致服务启动异常。# 启动服务并设置开机自启 sudo systemctl start named sudo systemctl enable named # 查看服务状态 sudo systemctl status named启动之后直接用本机验证dig 127.0.0.1 www.baidu.com如果能正常返回A记录说明缓存DNS已经可以工作了。2.4 让服务开机自启并放行防火墙端口一个很常见的现象是DNS服务配置好了测试也能解析但服务器一重启就失灵。原因基本是没设置enable或者防火墙把53端口挡了。RPM系和Debian系默认防火墙规则差异很大Ubuntu默认可能没有安装UFW规则但Rocky和CentOS默认开启firewalld此时必须放行DNS服务。sudo firewall-cmd --permanent --add-servicedns sudo firewall-cmd --reloadDebian系如果是云服务器还要留意安全组规则很多时候服务端配置全对问题出在云控制台没放开UDP/TCP 53端口。DNS查询默认是UDP 53但在区域传输或响应超过512字节时可能走TCP 53所以我建议UDP和TCP都放行避免排查到怀疑人生。3. 配置正向解析与反向解析3.1 正向区域文件写法与SOA、NS、A、CNAME、MX记录缓存DNS搞定后更有技术含量的部分就是配置权威区域也就是自己管理一个域名空间的解析记录。最典型的需求是给内网建一个类似example.internal的域名然后把公司的gitlab.example.internal、wiki.example.internal、jenkins.example.internal这些内部系统都纳入统一解析。在named.conf或区域配置目录里声明一个zonezone example.internal { type master; file example.internal.zone; allow-update { none; }; };然后创建区域文件/var/named/example.internal.zone。RPM系默认区域文件的属组是named:named权限一般设为640否则named进程可能没有权限读取导致区域加载失败。$TTL 1D IN SOA ns1.example.internal. admin.example.internal. ( 2025032701 ; serial 3H ; refresh 15M ; retry 1W ; expire 3H ) ; minimum IN NS ns1.example.internal. ns1 IN A 192.168.1.53 www IN A 192.168.1.80 gitlab IN A 192.168.1.81 wiki IN CNAME gitlab.example.internal. IN MX 10 mail.example.internal. mail IN A 192.168.1.82这里面有几个关键点需要理解。SOA记录是区域文件的“头”里面最重要的是serial字段它是一个版本号。主备同步、修改记录后通知备机都靠它判断是否有更新我每次改记录都会习惯性地按照日期加序号更新比如2025032701这已经是运维惯用的方式了。NS记录声明这个区域由哪台DNS服务器负责。注意这里写的是域名不是IP所以必须同时给这个域名配上A记录形成“胶水记录”。A记录是最常用的把主机名解析到IPv4地址。CNAME记录给已有主机名起别名比如wiki和gitlab指向同一台服务器就适合用CNAME。MX记录是邮件交换记录如果你的内网有自己的邮件系统会用到它。3.2 反向解析PTR记录反向解析是把IP地址解析成域名排查网络问题、邮件服务器反垃圾验证时经常会用到。内网环境如果不想做反向解析一般不影响使用但作为完整DNS服务器配置我建议还是掌握。反向区域名有个固定写法把IP地址反过来写再加上in-addr.arpa。比如192.168.1.0/24网段反向区域名就是1.168.192.in-addr.arpa。zone 1.168.192.in-addr.arpa { type master; file 192.168.1.zone; };区域文件内容如下$TTL 1D IN SOA ns1.example.internal. admin.example.internal. ( 2025032701 ; serial 3H ; refresh 15M ; retry 1W ; expire 3H ) ; minimum IN NS ns1.example.internal. 53 IN PTR ns1.example.internal. 80 IN PTR www.example.internal. 81 IN PTR gitlab.example.internal.注意PTR记录左边只写IP最后一段因为前面的网段已经包含在区域名里了。3.3 为内网域名配置转发与递归限制很多教程到这里就结束了但在企业真实场景里正向、反向区域和递归策略通常是同时生效的。也就是说同一台DNS服务器既负责内部域名example.internal的权威解析又负责客户端对公网域名的递归查询。这种场景下务必要设置allow-recursion避免对外开放递归。如果把自己搭的DNS暴露出去了任何人都能用你的服务器做解析轻则被刷流量重则被利用做放大攻击。配置上我建议在options里单独限定递归权限不要把递归开放给所有IP。如果需要让内网的少数几台服务器通过这台DNS解析公网域名而其余设备走自己的网络配置也可以通过acl配合实现acl internal_net { 127.0.0.0/8; 192.168.1.0/24; 10.0.0.0/8; }; options { allow-query { internal_net; }; allow-recursion { internal_net; }; };3.4 配置变更后的加载与验证改完区域文件和主配置文件不要直接重启而是先检查语法。named-checkconf检查主配置named-checkzone检查区域文件。我在刚开始配置BIND时经常漏掉这个步骤结果重启后服务起不来还得来回看日志效率很低。sudo named-checkconf /etc/named.conf sudo named-checkzone example.internal /var/named/example.internal.zone如果没有输出错误再用rndc reload重新加载配置这个命令支持在线重载不用中断DNS服务。RPM系重载后可以用journalctl -u named -f观察日志确认没有加载报错。sudo rndc reload4. 管理DNS服务器的常用操作与排查工具4.1 服务管理日志查看systemctl、journalctl、named-checkconfDNS服务器的日常管理绕不开服务状态查看和日志分析。systemctl status named只能看到服务的整体状态真正定位问题还是要看日志。RPM系的named默认把日志输出到/var/named/data/named.run同时也记录在journald里。我排查DNS问题时有一个固定节奏先systemctl status named确认进程在不在再用journalctl -u named -n 100 --no-pager拉最近日志最后根据日志里的关键词顺藤摸瓜。比如看到file not found就是区域文件路径不对看到permission denied就是权限或SELinux问题看到bad zone transfer就是主备配置问题。另外要养成改配置前备份的习惯。生产服务器上我会把配置文件纳入git管理每次变更都留一个版本出现问题能快速回滚。这个习惯在排查问题时帮助巨大。4.2 解析测试三件套dig、nslookup、host解析排错的时候命令行的三个工具要熟练使用。nslookup是最经典的工具适合快速验证某条记录是否正常。dig的功能最丰富是排查DNS问题的首选host则适合脚本里做简单的域名解析验证。# 指定DNS服务器查询 dig 127.0.0.1 www.example.internal # 查询MX记录 dig 127.0.0.1 example.internal MX # 查询CNAME记录 dig 127.0.0.1 wiki.example.internal CNAME # 反向解析 dig -x 192.168.1.81 127.0.0.1 # 跟踪完整解析链路 dig trace www.baidu.com 127.0.0.1dig trace这个参数值得单独说一说。它会一步步展示从根服务器到顶级域、再到权威服务器的完整解析过程当遇到“为什么这台服务器解析结果和别的机器不一样”这种问题时trace能直接告诉你问题出在链路的哪一环。还有dig short适合脚本里提取解析结果只输出IP或CNAME干净利落。4.3 常见故障fe80::1%11、dns服务器无法访问接着说说真实环境里最容易碰到的几个坑。一个是Windows电脑命令提示符里执行ipconfig /all时DNS服务器列表出现fe80::1%11这种IPv6链路本地地址而DNS解析时好时坏。这个情况通常是路由器或网卡启用了IPv6自动下发了IPv6的DNS地址但网络环境本身没有正确配置IPv6路由导致解析请求发出去没回应。排查方式很简单先把IPv6的DNS设置停掉或者手动把DNS改成IPv4地址看问题是否消失。另一个高频问题是“DNS服务器无法访问”。遇到这个提示先在客户端上分别测试ping DNS服务器的IP看是否通telnet DNS服务器53端口看端口通不通用dig DNS服务器IP 某个域名看有没有响应。这样能快速定位是网络不通、防火墙拦截还是服务本身挂了。我见过一些人一遇到这个问题就重装系统结果发现只是虚拟机的网卡没有接入同一个虚拟网络白白折腾半天。还有一个小问题很隐蔽在Linux上手动改了/etc/resolv.conf重启后发现配置被覆盖。这是因为NetworkManager或systemd-resolved会自动管理这个文件。正确的做法是修改网络管理工具的DNS配置比如nmcli con mod ens33 ipv4.dns 192.168.1.53或者使用nmcli重新加载连接而不是直接改resolv.conf。5. 配置与管理中的常见坑和避坑经验5.1 权限、SELinux、防火墙是“三大拦路虎”在RPM系系统上配置DNS服务器权限、SELinux、防火墙这三样东西经常轮番出来添乱。区域文件如果放在/var/named/下默认属主和属组是root:named权限640。如果文件属组不对或者权限过宽named进程可能直接拒绝读取服务状态看起来是active但解析就是失败日志里也只会留下模棱两可的提示。SELinux这边默认Enforcing模式下named的访问限制很严格区域文件如果放在自定义目录不设置正确的SELinux上下文named照样读不了。最简单安全的方式是把区域文件放到/var/named/或者/var/named/chroot/老版本常见如果放自定义目录要执行sudo semanage fcontext -a -t named_zone_t /data/named/example.internal.zone sudo restorecon -v /data/named/example.internal.zone防火墙的问题前面提过这里再强调一次firewalld没有放行DNS服务外部客户端永远解析不了而本机dig却正常这种情况最容易让人误判成客户端配置错误。5.2 日志与时间同步DNS大小事都可能被它坑DNS是强依赖时间的服务之一尤其是涉及到DNSSEC验证时如果服务器时间与真实时间偏差过大会出现验证失败、解析异常的情况。内网有多台服务器的话务必统一配置NTP时间同步。我在维护环境时发现DNS服务器的日志如果开启得足够详细比如记录所有查询日志会对排错很有帮助但生产环境要注意性能开销可以按需开启比如只在排查期间开或者只记录失败查询。logging { channel query_log { file /var/log/named-query.log versions 3 size 20m; severity info; print-time yes; }; category queries { query_log; }; };5.3 配置变更后不生效serial和缓存是关键有一种特别让人抓狂的情况明明改了区域文件用rndc reload也提示成功但客户端查到的还是旧IP。这时候十有八九是SOA记录里的serial没有递增。主从同步时备机靠serial判断区域是否变化如果你没更新serial备机认为区域没变就不会同步。即使只有一台DNS服务器有些客户端和上级DNS也会因为缓存机制继续返回旧记录。修改记录的规范流程是先改区域文件然后同步把serial加一接着named-checkzone验证再rndc reload。如果客户端还是拿到旧记录可以检查客户端的DNS缓存Windows上使用ipconfig /flushdnsLinux上根据发行版使用systemd-resolve --flush-caches或重启相关服务。5.4 安全加固限制递归、限制传输、控制查询最后聊一聊安全加固。自建的DNS服务器如果暴露在公网或不可信网络至少要做三层加固限制递归、限制区域传输、隐藏版本信息。限制递归前面讲过通过allow-recursion只放行内网网段。限制区域传输用allow-transfer主DNS只允许备机IP拉取区域数据不允许其他客户端随意发起AXFR请求防止内网DNS记录被批量窃取。隐藏版本信息是在options里设置version none避免被别人轻易探测到BIND版本号。options { version none; allow-transfer { 192.168.1.54; }; allow-recursion { localhost; 192.168.1.0/24; }; };要是内网规模比较大还需要考虑主从部署给每台DNS配置一个备机保证单点故障时解析不中断。主从的配置其实不复杂主服务器允许备机传输备机上配相同区域、type改为slave然后指定主服务器IP。这个方向后续可以单独拉一篇来讲这里先不展开。配置和管理DNS服务器说白了就是“先角色定位、再配置文件、后区域数据、终调试优化”的过程。BIND的细节很多但核心概念其实就那么几个把SOA、serial、递归、转发、ACL这几个点吃透大部分场景都能覆盖。我在实际配置中踩过不少坑比如刚开始不知道要更新serial改完记录发现没生效比如没考虑SELinux区域文件放自定义目录怎么都加载不了再比如IPv6的DNS自动下发导致客户端解析结果飘忽不定。这些经验写出来就是希望大家少走这些弯路。如果你按这篇文章的思路搭好了一台基础DNS服务器也可以继续尝试做主从同步、配置日志记录、甚至做简单的智能解析这些都是DNS管理里非常实用的扩展方向。