首页 / 资讯中心 / 文章详情

RHEL 8 内网 DNS 服务搭建实战:BIND 正向反向解析与排错指南

RHEL 8 内网 DNS 服务搭建实战:BIND 正向反向解析与排错指南 ★ FEATURED ARTICLE
1. 为什么要在 RHEL 8 上自己搭 DNS而不是随便找个现成的很多人第一次接触 DNS 服务搭建脑子里冒出来的第一个念头是直接用运营商给的 DNS 不就行了。这个想法在个人上网场景下没毛病但只要涉及到内网环境问题就来了。我见过太多小团队的内网里机器之间互相访问全靠 IP运维换一台服务器就得挨个通知所有人改配置时间一长连自己都记不清哪个 IP 对应哪台机器。这种环境下一套自己可控的 DNS 服务就不是锦上添花而是雪中送炭。RHEL 8 这个版本在 DNS 服务这块有个比较大的变化就是它默认的 DNS 服务端软件从老版本的 bind 换成了 bind 9.11 系列配置文件的组织方式、目录结构、以及和 SELinux、firewalld 的配合方式都和 RHEL 7 有区别。如果你拿着 RHEL 7 时代的教程直接往 RHEL 8 上套大概率会在权限和防火墙这两个环节卡住。这也是为什么我决定把整个搭建过程重新梳理一遍把那些教程里不写但实际会踩的坑都摊开来讲。这篇文章面向的是有一定 Linux 基础、需要在 RHEL 8 环境里搭建内网 DNS 服务的运维人员或者开发同学。我会从软件选型、安装、配置、验证、排错这几个维度完整走一遍重点放在为什么这么配而不是照着敲命令。你跟着走完一遍应该能独立搭出一套支持正向解析、反向解析、转发查询的基础 DNS 服务并且知道出问题的时候该往哪个方向查。提示本文所有操作均在 RHEL 8.0 的最小化安装环境下验证如果你的系统装了图形界面或者额外的安全组件部分步骤可能需要微调。2. 动手之前先把这几个概念理清楚2.1 正向解析和反向解析到底在解决什么问题DNS 的核心工作说白了就两件事把域名翻译成 IP把 IP 翻译回域名。前者叫正向解析后者叫反向解析。正向解析是日常用得最多的比如你访问一个内部系统app.internal.lab浏览器需要知道它对应的 IP 是多少。反向解析用得少一些但在日志分析、邮件服务、安全审计这些场景里很关键——你拿到一堆访问日志全是 IP没有反向解析就得手动一个个查。在 BIND 的配置里正向解析对应的是区域文件里的 A 记录反向解析对应的是 PTR 记录。这两个记录存在不同的区域文件里配置的时候要分别建。很多人搭 DNS 只配了正向结果邮件服务发信被拒排查半天才发现是反向解析没做。所以我的建议是一开始就把正反两个方向都配好省得后面返工。2.2 主 DNS、从 DNS、缓存 DNS 的角色区别BIND 可以扮演三种角色。主 DNS 是权威数据的来源所有区域文件的原始版本都在它这里。从 DNS 通过区域传送从主 DNS 同步数据起到冗余和负载分担的作用。缓存 DNS 不存权威数据只负责把查询过的结果缓存下来加速后续查询。内网环境里最常见的是一主一从或者单主的架构。如果你的内网规模不大单台主 DNS 就够了。但如果这台机器挂了整个内网的名字解析就全瘫了所以有条件的话还是建议配一台从 DNS。缓存 DNS 一般用在出口位置帮内网用户加速外部域名解析这个场景下它和转发器的功能有重叠具体用哪个看你的网络架构。2.3 RHEL 8 里 BIND 的目录布局和 RHEL 7 有什么不同这是很多人容易忽略的地方。RHEL 8 里 BIND 的主配置文件还是/etc/named.conf但区域文件的默认存放目录变成了/var/named/而且这个目录的 SELinux 上下文是专门设置过的。如果你把区域文件放到别的地方比如/etc/named/或者自己建的/data/dns/SELinux 会直接拦下来日志里报的是permission denied但你看文件权限明明是 644这就是典型的 SELinux 上下文问题。另外 RHEL 8 默认启用了named服务的 systemd 单元启动方式和 RHEL 7 的systemctl start named一样但日志查看方式变了推荐用journalctl -u named而不是直接看/var/log/messages。这些细节在后面配置和排错的时候都会用到。3. 安装和基础环境准备那些教程里不写的细节3.1 软件包安装与依赖确认RHEL 8 的软件仓库里BIND 相关的包主要有三个bind是主程序bind-utils提供dig、nslookup、host这些诊断工具bind-chroot是可选的沙箱环境。我一般会把前两个都装上bind-chroot看情况——它能把 BIND 的运行环境限制在一个子目录里安全性更好但配置路径会变得稍微绕一点新手容易搞混。安装命令很简单dnf install bind bind-utils -y装完之后先别急着启动用rpm -ql bind | head -30看一眼文件都装到哪了。你会看到主配置文件在/etc/named.conf区域文件模板在/usr/share/doc/bind/sample/下面实际运行时的区域文件目录是/var/named/。这个/var/named/目录在安装后是空的需要你自己往里放文件。注意RHEL 8 默认的named.conf里已经包含了一些基础配置不要直接覆盖建议先备份再改。3.2 SELinux 和 firewalld 的前置处理这两个是 RHEL 8 上搭 DNS 最容易翻车的地方。SELinux 默认是 enforcing 模式firewalld 默认也是开启的。如果你不处理这两块BIND 要么起不来要么起来了但外部查不了。SELinux 这块BIND 相关的布尔值有好几个最常用的是named_write_master_zones如果你需要动态更新区域文件就得开这个。但基础的正向反向解析不需要动布尔值只要保证区域文件放在/var/named/下并且上下文正确就行。检查上下文用ls -lZ /var/named/如果上下文不对用restorecon -Rv /var/named/修复。firewalld 这块DNS 用的是 53 端口的 TCP 和 UDP放行命令firewall-cmd --permanent --add-servicedns firewall-cmd --reload这里有个细节DNS 查询主要走 UDP但区域传送和超过 512 字节的响应会走 TCP所以两个协议都要放。只放 UDP 的话小查询没问题一旦响应大了或者做区域传送就会失败而且失败得很隐蔽日志里不一定有明确报错。3.3 主机名和网络配置的确认BIND 启动的时候会读取本机的主机名如果主机名解析有问题服务可能启动异常。建议先把/etc/hosts里加上本机主机名和 IP 的对应关系比如192.168.1.10 dns.internal.lab dns同时用hostnamectl set-hostname dns.internal.lab把主机名设好。这一步看起来多余但实际能避免很多服务起不来但不知道为啥的问题。我遇到过好几次因为主机名是默认的localhost导致 BIND 启动时报错的情况排查半天才发现是主机名的问题。4. 主配置文件 named.conf 的逐段拆解4.1 options 段监听、转发、递归怎么配/etc/named.conf的options段是整个服务的全局设置几个关键参数必须搞清楚。listen-on port 53决定 BIND 监听哪个 IP 和端口。默认是listen-on port 53 { 127.0.0.1; };意思是只监听本地回环。如果你要让内网其他机器能查得改成服务器的实际 IP比如listen-on port 53 { 127.0.0.1; 192.168.1.10; };。这里有个坑如果你写any虽然能工作但 SELinux 和防火墙的配合会更复杂而且安全性差不推荐。allow-query控制哪些客户端可以查询。默认也是只允许本地要改成你的内网网段比如allow-query { localhost; 192.168.1.0/24; };。这个参数和listen-on是两回事前者管听不听后者管让不让查两个都要配。forwarders是转发器当 BIND 自己解析不了某个域名时把请求转发给上游 DNS。内网环境一般填运营商的 DNS 或者公司统一的出口 DNS。forward only表示只转发不自己递归forward first表示先转发转发失败再自己递归。内网场景用forward first比较稳妥。recursion yes表示允许递归查询。如果你的 DNS 只服务内网这个开着没问题。但如果你的 DNS 暴露在公网一定要关掉否则会被利用做 DNS 放大攻击。4.2 区域声明zone 段的写法与常见错误zone段是告诉 BIND 我负责哪个域名的解析。正向区域的写法zone internal.lab IN { type master; file internal.lab.zone; allow-update { none; }; };反向区域的写法稍微绕一点因为反向区域的名字是 IP 段倒过来加.in-addr.arpa。比如192.168.1.0/24这个网段反向区域名就是1.168.192.in-addr.arpazone 1.168.192.in-addr.arpa IN { type master; file 1.168.192.rev; allow-update { none; }; };这里最常见的错误是反向区域名写错。192.168.1.0/24倒过来是1.168.192不是192.168.1也不是0.1.168.192。写错了 BIND 启动不报错但反向查询就是没结果排查起来很费劲。allow-update { none; }表示不允许动态更新静态配置的场景下这样最安全。如果你需要 DHCP 配合动态更新 DNS才需要改成允许特定密钥更新。4.3 日志配置出问题时怎么快速定位BIND 默认的日志走 syslog用journalctl -u named能看到。但默认日志级别信息量不够排查问题的时候经常看不出所以然。建议在named.conf里加一段 logging 配置把查询日志和错误日志分开logging { channel default_log { file /var/log/named/named.log versions 3 size 20m; severity info; print-time yes; print-category yes; print-severity yes; }; category default { default_log; }; category queries { default_log; }; };注意/var/log/named/这个目录要自己建并且属主设成named否则 BIND 写不进去。SELinux 对日志目录也有上下文要求建完目录后跑一下restorecon -Rv /var/log/named/。提示查询日志在调试阶段很有用但生产环境长期开着会占不少磁盘调通之后建议把category queries那行注释掉。5. 区域文件的编写正向和反向的实操细节5.1 正向区域文件的记录类型与写法正向区域文件放在/var/named/下文件名要和named.conf里file参数写的一致。一个典型的正向区域文件长这样$TTL 86400 IN SOA dns.internal.lab. admin.internal.lab. ( 2024010101 ; serial 3600 ; refresh 1800 ; retry 604800 ; expire 86400 ; minimum ) IN NS dns.internal.lab. IN A 192.168.1.10 dns IN A 192.168.1.10 app IN A 192.168.1.20 db IN A 192.168.1.30 www IN CNAME app.internal.lab.几个关键点。SOA记录里的 serial 是版本号每次改区域文件都要递增否则从 DNS 不会同步。格式一般是年月日加两位序号比如2024010101。refresh、retry、expire、minimum这四个是 SOA 的标准参数单位是秒内网环境用默认值就行。NS记录声明这个区域的权威 DNS 是哪台机器后面必须跟完整域名并且以点结尾。A记录是核心把主机名映射到 IP。CNAME是别名指向另一个域名而不是 IP注意 CNAME 不能和其他记录共存于同一个名字上。文件写完后权限要设对chown root:named /var/named/internal.lab.zone chmod 640 /var/named/internal.lab.zone属组是named权限 640这样 BIND 能读但其他人读不了。5.2 反向区域文件的 PTR 记录写法反向区域文件的结构和正向类似但记录类型主要是 PTR$TTL 86400 IN SOA dns.internal.lab. admin.internal.lab. ( 2024010101 3600 1800 604800 86400 ) IN NS dns.internal.lab. 10 IN PTR dns.internal.lab. 20 IN PTR app.internal.lab. 30 IN PTR db.internal.lab.注意 PTR 记录前面的名字只写 IP 的最后一段。比如192.168.1.20对应的 PTR 记录名字就是20BIND 会自动补上区域名1.168.192.in-addr.arpa。这里写错了会导致反向解析失败而且不会有明显报错。5.3 区域文件语法检查的两种方法写完区域文件别急着重启服务先用工具检查语法。named-checkzone是专门检查区域文件的named-checkzone internal.lab /var/named/internal.lab.zone named-checkzone 1.168.192.in-addr.arpa /var/named/1.168.192.rev输出zone internal.lab/IN: loaded serial 2024010101就说明没问题。如果有语法错误它会指出具体行号和错误类型。主配置文件用named-checkconf检查named-checkconf /etc/named.conf这个命令没有输出就表示配置正确。养成改完必查的习惯能省掉大量重启服务后排查问题的时间。6. 服务启动、验证与常见故障排查6.1 启动服务并确认监听状态配置检查通过后启动服务systemctl enable --now named systemctl status named状态显示active (running)就说明起来了。再用ss -tulnp | grep named确认 53 端口在监听应该能看到 TCP 和 UDP 各一行。如果服务起不来第一件事是看日志journalctl -u named -n 50 --no-pager常见的启动失败原因有几个区域文件权限不对、SELinux 拦截、配置文件语法错误、53 端口被占用。日志里一般会给出具体原因按提示排查就行。6.2 用 dig 验证正向和反向解析验证正向解析dig 192.168.1.10 app.internal.lab看返回的ANSWER SECTION里有没有对应的 A 记录status是不是NOERROR。如果status是SERVFAIL多半是区域文件有问题如果是REFUSED是allow-query没放行你的客户端 IP。验证反向解析dig 192.168.1.10 -x 192.168.1.20-x参数会自动把 IP 转成反向查询格式。返回的ANSWER SECTION里应该有 PTR 记录。验证转发dig 192.168.1.10 www.example.com如果返回了结果说明转发器工作正常。如果超时检查forwarders配置和上游 DNS 的连通性。6.3 排查链路从客户端到服务端的完整检查顺序DNS 查询失败的时候按这个顺序排查效率最高。第一步在服务端本机用dig 127.0.0.1查排除网络问题。如果本机都查不了问题在 BIND 本身。第二步从客户端用dig 服务端IP查排除防火墙问题。如果本机行、远程不行检查 firewalld 和allow-query。第三步检查 SELinux 是否拦截。用ausearch -m avc -ts recent看有没有和 named 相关的拒绝记录。有的话用audit2allow分析或者直接把区域文件放到正确目录并restorecon。第四步检查区域文件的 serial 和语法。用named-checkzone重新验证一遍。第五步看 BIND 日志里有没有具体的错误信息。查询日志能告诉你请求有没有到达 BIND错误日志能告诉你处理过程中出了什么问题。这个顺序的核心逻辑是从内到外、从简到繁先排除服务本身的问题再排除网络和权限的问题最后才怀疑配置细节。按这个顺序走大部分问题能在前三步定位到。7. 几个实际运维中总结出来的经验区域文件的 serial 号一定要养成递增的习惯。我见过有人改了区域文件忘了改 serial结果主从不同步从服务器上查到的还是旧数据排查了半天才发现是 serial 没变。建议每次改完区域文件把 serial 改成当前日期加序号比如2024011501这样一眼就能看出最后修改时间。allow-query和listen-on这两个参数建议一开始就配好不要图省事写any。内网环境写具体的网段既安全又清晰。如果后面网络结构调整了改这两个参数比改防火墙规则直观得多。日志目录/var/log/named/记得定期清理。查询日志在调试阶段很有用但长期开着一天能写几百 MB磁盘满了 BIND 会直接挂掉。我的做法是调试完就把category queries注释掉只保留错误日志然后配个 logrotate 定期切割。最后说一个容易被忽略的点BIND 的配置文件改完之后用systemctl reload named比restart更平滑。reload会重新读取配置但不中断已有连接restart会短暂中断服务。生产环境优先用reload但如果改的是listen-on这种涉及端口监听的参数还是得restart才能生效。
阅读完成 · 觉得有帮助?
咨询建站