在Linux下DNS服务启动不了?手把手教你排查与解决
作为一名Linux运维工程师,最怕的就是半夜被电话叫醒:“DNS解析不了啦!网站打不开啦!”我遇到过很多次,冲进机房一看,服务没起来,或者重启失败,就说说最常见的DNS服务(BIND/Named、dnsmasq或systemd-resolved)启动不了的情况吧,今天把这几年的踩坑经验整理一下,希望能帮到正在对着终端发愁的你。
先别慌,看看日志再说
不管你是用systemctl还是service命令,DNS服务启动不了的时候,第一反应应该是看日志,很多新手会反复重启,但重启一百次也没用,因为根本原因没找到。
对于BIND(named),日志默认在/var/log/messages或/var/log/named.log,具体看你的rsyslog配置,对于dnsmasq,日志一般在/var/log/daemon.log或journalctl里,systemd-resolved的话,直接journalctl -u systemd-resolved。
举个例子,我前两天刚处理过一个named启动失败:
journalctl -u named -n 50
输出里看到一行:
named[12345]: loading configuration from '/etc/named.conf' named[12345]: /etc/named.conf:54: unknown option 'allow-recursion'
这不就是配置文件写错了嘛!allow-recursion拼写?不,是语法格式不对,BIND的配置文件非常敏感,分号、花括号、引号一个都不能少,很多时候启动不了就是因为配置文件里有语法错误。
常见原因一:配置文件语法错误
这是最频繁的问题,比如你手动改了named.conf,或者从别处复制了一份,结果少了一个分号:
options {
directory "/var/named";
allow-query { any; }; // 这里忘了加分号?不,是括号不匹配
};如果少了一个},BIND会直接报“unexpected end of file”,怎么检查?用named-checkconf命令:
named-checkconf /etc/named.conf
它会告诉你在哪一行少了什么,如果没报错,那基本语法没问题,同理,dnsmasq也有dnsmasq --test来检查配置。
常见原因二:端口被占用
DNS默认使用UDP和TCP的53端口,如果其他服务(比如另一个DNS服务、或者你装的某个代理软件)占用了53,那肯定启动不了。
检查端口占用:
ss -tulpn | grep :53
如果看到类似:
udp UNCONN 0 0 0.0.0.0:53 0.0.0.0:* users:(("systemd-resolved",pid=1234,fd=17))说明systemd-resolved已经占用了53端口,有些发行版(如Ubuntu 18.04+)默认启用systemd-resolved,你再装BIND,两者冲突,解决办法:要么停用systemd-resolved,要么把BIND改到其他端口(生产环境不推荐),或者调整systemd-resolved的监听地址。
曾经我碰到过一个案例:在容器里启动named,死活报“permission denied”,但用户是root,折腾了半天才发现,是因为Docker容器的网络模式是host,主机上的另一个服务已经占用了53,白费了半天时间。
常见原因三:权限问题(SELinux、AppArmor、文件属主)
Linux的安全机制有时候比女朋友还难捉摸,SELinux(红帽系)和AppArmor(Ubuntu/Debian)都会限制服务的访问权限。
你新添加了一个zone文件,放在/var/named/myzone.com.zone,结果named报:
named: loading zones: permission denied
这时候先检查SELinux上下文,用ls -Z看文件的安全上下文:
ls -Z /var/named/myzone.com.zone
正常应该是system_u:object_r:named_zone_t:s0,如果是user_tmp_t之类的,就需要恢复:
restorecon -v /var/named/myzone.com.zone
或者干脆临时关掉SELinux(仅测试用):
setenforce 0
再启动试试,如果好了,那就是SELinux的锅,永久解决的话,写个策略或者直接改/etc/selinux/config(不建议生产关)。
AppArmor类似,journalctl -u apparmor能看拒绝记录。
文件属主和权限也重要,named的zone文件一般属主是named:named,权限640或644,你用chown named:named一下就好。
常见原因四:网络接口配置问题
有时候DNS服务启动成功了,但客户端就是解析不了,那是因为监听地址不对。
默认情况named监听在localhost(127.0.0.1)和本机IP,如果你的服务器有多个网卡,或者需要对外提供服务,记得在配置里明确写监听地址:
options {
listen-on port 53 { 127.0.0.1; 192.168.1.10; };
listen-on-v6 port 53 { ::1; };
};如果只写了127.0.0.1,局域网其他机器就访问不到,这是低级错误,但很常见。
别忘了检查防火墙,CentOS/RHEL的firewalld或Ubuntu的ufw可能挡住了53端口,先试一下:
firewall-cmd --list-all
如果没有放行dns服务:
firewall-cmd --permanent --add-service=dns firewall-cmd --reload
常见原因五:资源不足(内存、文件描述符)
DNS服务本身占内存不大,但如果配置文件里写了大量的zone,或者开启了递归查询,内存可能会爆,可以用free -m看一眼,BIND在内存不足时会启动失败,或者启动后自动退出。
还有文件描述符限制,如果系统默认的ulimit -n是1024,而BIND需要更多的并发连接,可能会报“too many open files”,检查/etc/security/limits.conf或systemd service文件里的LimitNOFILE。
实战案例:一个完整的排查过程
前几天有个客户服务器CentOS 7,DNS突然挂了,重启named无效,我远程过去,做了一遍标准流程:
1、systemctl status named 显示failed,最后一句是“access denied when opening zone file”。
2、journalctl -xe 看到权限错误。
3、ls -lZ /var/named/chroot/var/named/ 发现新加的zone文件SELinux上下文是unconfined_u:object_r:default_t。
4、运行restorecon -R /var/named/chroot/var/named/,再重启。
5、还不行?再看日志:“could not configure listening sockets: address in use”。
6、ss -tulpn | grep :53 发现系统有一个dnsmasq在监听。
7、systemctl stop dnsmasq && systemctl disable dnsmasq,再start named。
8、成功!顺便检查了防火墙,确保53端口开放。
整个过程不到10分钟,但如果没有系统性的排查思路,新手可能就卡在第一步。
排查六步法
下次遇到DNS启动不了,按顺序来:
1、查日志 – journalctl或/var/log/messages。
2、语法检查 – named-checkconf、dnsmasq --test。
3、端口冲突 – ss -tulpn | grep :53。
4、SELinux/AppArmor – getenforce、ausearch、restorecon。
5、文件权限 – 属主、群组、目录层次。
6、防火墙 – firewalld、iptables、ufw。
如果是systemd-resolved的问题(很多Ubuntu用户会遇到),可以临时切换成dnsmasq或直接卸载resolved,但要做好备份。
最后说一句:不要在生产环境上直接改配置然后立即重启,先备份、再测试、再重启,最好先改配置后执行named-checkconf,没问题再systemctl reload named(热加载),这个比重启风险小。
希望这篇文章能帮你少摔几次坑,如果还有什么奇葩问题,欢迎留言交流——毕竟,我们运维的日常,就是解决一个又一个“为什么启动不了”。
文章摘自:https://idc.huochengrm.cn/dns/25873.html
评论