从零搭建内网DNS服务:dnsmasq与BIND选型、配置与排错实战
1. 为什么还要自己搭 DNS 服务很多人第一次听到“自建 DNS”都会有一个疑问运营商不是已经给了 DNS 吗公共 DNS 也一大把为什么还要自己折腾一台我刚开始也是这么想的直到手里设备一多、内网服务一多才发现默认那套解析方式根本不够用。最直接的痛点有三个。第一是内网域名解析。家里或小团队里跑着 NAS、软路由、开发测试环境、数据库、监控面板如果每次都靠 IP 访问记不住不说换一台机器所有配置都得跟着改。第二是解析速度和缓存命中。默认 DNS 经常被塞一堆无关记录访问常用站点时延忽高忽低自建一个带缓存的递归或转发解析常用域名基本是毫秒级返回。第三是可控性。哪些域名走哪个上游、哪些广告域名直接拦掉、哪些内网域名只在内网可见这些只有自己掌控解析链路才能做到。这篇内容就是把我自己从零搭一套 DNS 服务的完整过程拆开讲。DNS 服务搭建这件事听起来专业其实核心就三块选软件、配解析、做验证。我会把每一步为什么这么做、参数怎么算、坑在哪里都写清楚。适合手里有闲置机器物理机、虚拟机、容器都行、想给内网做一套稳定域名解析的人也适合刚接触网络服务、想拿 DNS 练手的朋友。哪怕你之前没碰过 named 或 dnsmasq跟着走也能跑起来。需要先说明一点下面所有示例里的域名、IP 段、主机名都是演示用的占位内容你实际部署时替换成自己的规划即可。整套方案不依赖任何特定厂商纯靠开源软件就能完成。2. 方案选型与整体架构设计2.1 三种主流 DNS 软件到底怎么选自建 DNS 绕不开三个名字BIND、dnsmasq、CoreDNS或者更轻的 Unbound。它们定位差别很大选错了后面会很难受。BIND 是 DNS 界的“老大哥”功能最全支持权威解析、递归解析、DNSSEC、视图view、区域传送等。缺点是配置文件语法偏啰嗦zone 文件格式对新手不友好一个分号写错就起不来。它适合需要权威递归一体、或者要给外部提供域名解析的场景。dnsmasq 走的是轻量路线配置就一个 conf 文件几行就能跑。它最大的优势是内置 DHCP DNS还能读 hosts 文件、支持通配符域名、支持上游分组。缺点是并发和缓存能力比 BIND 弱超大规模场景不合适。对家庭和小团队来说dnsmasq 是性价比最高的选择。CoreDNS 是云原生时代的产物插件化架构配置用类似 Caddy 的 Corefile 语法特别适合容器环境和 Kubernetes 内部解析。它做纯转发和自定义解析非常优雅但做传统权威 zone 管理不如 BIND 顺手。我个人的选型建议是这样的场景推荐软件理由家庭/小团队内网域名广告拦截dnsmasq配置简单DHCPDNS 一体需要权威解析、对外提供域名BIND功能完整生态成熟容器/K8s 环境CoreDNS插件灵活和编排系统贴合纯递归缓存加速Unbound专注递归安全加固好下面我以dnsmasq 为主、BIND 为辅的思路来讲因为这套组合覆盖了绝大多数人的真实需求dnsmasq 负责内网解析和缓存转发遇到需要权威 zone 的场景再上 BIND。2.2 整体解析链路怎么设计在动手之前先把数据流向想清楚否则配到一半会乱。一个典型的自建 DNS 架构是这样的客户端手机/电脑/服务器把 DNS 查询发给内网 DNS 服务器服务器先查自己的本地记录hosts、自定义域名、DHCP 租约命中就直接返回没命中就看缓存缓存有也直接返回还没有就按上游分组转发出去拿到结果后写入缓存再返回给客户端。这里有几个设计决策要提前定监听地址是只监听内网网卡还是所有网卡都监听如果机器有公网 IP强烈建议只监听内网地址避免被外部当成开放解析器滥用。上游选择用运营商 DNS 还是公共 DNS建议配两组以上一组主用一组备用避免单点。是否开启 DHCP如果 DNS 服务器同时要做网关或和 DHCP 在同一台机器可以让 dnsmasq 接管 DHCP这样客户端拿到的 DNS 地址自动指向自己省去手动配置。缓存大小dnsmasq 默认缓存 150 条内网设备多的话建议调到 1000 以上。注意开放递归解析器Open Resolver是常见的安全隐患。如果你的 DNS 服务器能被公网访问又没有做访问控制很容易被拿来做放大攻击。务必用防火墙限制 53 端口的来源或者只监听内网网卡。2.3 部署环境与前置准备我这次用的是一台内网虚拟机配置不高1 核 1G 就够跑 dnsmasq。系统是常见的 Linux 发行版网络规划如下演示用DNS 服务器内网 IP192.168.10.10内网网段192.168.10.0/24计划使用的内网域名后缀home.lan演示用实际可换成你自己的上游 DNS192.168.10.1本地网关和一组公共 DNS前置检查几件事确认 53 端口没有被 systemd-resolved 或别的服务占用确认服务器能正常访问上游 DNS确认防火墙规则允许内网访问 53 端口TCP 和 UDP 都要。这几点看着简单但后面排查问题时十有八九会回到这里。3. dnsmasq 核心配置逐项拆解3.1 安装与主配置文件结构安装本身没什么好说的各发行版包管理器一条命令的事。装完之后主配置文件通常在/etc/dnsmasq.conf但我更推荐的做法是主配置只留框架具体规则拆到/etc/dnsmasq.d/目录下按功能分文件管理。这样以后加一条规则不用在几百行里翻找也方便备份和迁移。主配置文件里我一般只保留这几类设置监听接口、上游服务器、缓存参数、日志、以及一行conf-dir/etc/dnsmasq.d/,*.conf把子目录引进来。子目录里再按10-listen.conf、20-upstream.conf、30-internal.conf、40-block.conf这样编号加载顺序一目了然。这种拆分方式的好处是当你需要临时禁用某类规则时只要把对应文件改名或移走重启服务即可不用动主配置。团队协作时也不容易冲突。3.2 监听、上游与缓存参数怎么定监听这块核心参数是interface和listen-address。如果你只想让内网网卡提供服务写interfaceeth1换成你的内网网卡名如果想精确到地址用listen-address192.168.10.10。两个都写也可以dnsmasq 会取并集。千万不要图省事写listen-address0.0.0.0然后机器又有公网 IP那等于把解析器敞开给全世界。上游服务器用server指定可以写多条。dnsmasq 默认会轮询所有上游但更稳的做法是用all-servers让它同时向所有上游发查询取最快返回或者用strict-order按顺序来。我实测下来内网有本地网关缓存的情况下把网关放第一条、公共 DNS 放后面命中率最高。缓存参数里最重要的是cache-size。默认 150 对家庭够用但设备一多、访问域名一杂缓存频繁淘汰会拖慢解析。我一般设成cache-size2000内存占用也就几 MB很划算。另外neg-ttl可以设置否定缓存NXDOMAIN的时长默认偏短设成 60 秒能减少对不存在域名的重复查询。还有一个容易被忽略的参数是dns-forward-max它控制同时转发的查询上限默认 150。内网设备多、并发高的时候可以适当调大比如 300避免高峰期查询被丢弃。3.3 内网域名与 hosts 记录写法内网域名解析是自建 DNS 最实用的功能。dnsmasq 支持两种写法一种是用address直接把某个域名指向固定 IP另一种是用host-record定义主机记录。address/nas.home.lan/192.168.10.20这种写法会把nas.home.lan以及它的所有子域名都解析到指定 IP适合做通配。host-recordnas.home.lan,192.168.10.20则更规范只解析这一个名字还能同时定义 IPv4 和 IPv6。如果内网主机多一条条写太累可以直接让 dnsmasq 读系统的/etc/hosts加一行addn-hosts/etc/hosts即可。这样你维护 hosts 文件就等于维护 DNS 记录非常省事。我通常把静态服务器写进 hosts把需要通配的域名用address单独处理。提示address的匹配是“后缀匹配”address/home.lan/192.168.10.20会匹配a.home.lan、b.home.lan等所有子域。如果你只想匹配精确域名用host-record更安全避免误伤。3.4 上游分组与分流策略真正体现自建 DNS 价值的地方是分流。dnsmasq 支持给不同的域名指定不同的上游服务器语法是server/域名/上游IP。举个例子内网域名home.lan只应该由内网解析那就写server/home.lan/192.168.10.10把它指回自己避免泄露到上游。某些特定域名想走特定线路也可以用这个语法指定。反过来如果想让某些域名不走默认上游用server/域名/#表示“这个域名只用本地记录解析不转发”。分流规则写多了容易乱我的经验是按用途分文件内网域名一个文件特殊上游一个文件拦截规则一个文件。每个文件头部写清楚用途和修改日期半年后回来看还能秒懂。4. 完整实操流程与验证方法4.1 从零到跑通的完整步骤下面是我实际部署时走的流程按顺序执行即可。第一步安装 dnsmasq 并停掉可能冲突的解析服务。很多系统默认跑着 systemd-resolved它占着 53 端口会导致 dnsmasq 起不来。处理方式是禁用它的 DNS 监听保留其他功能或者直接停用。这一步不做后面一定报“address already in use”。第二步规划并创建配置目录。把主配置精简子配置按编号建好。我习惯先建一个00-base.conf放监听和缓存再建10-upstream.conf放上游20-internal.conf放内网记录30-block.conf放拦截。第三步写入具体规则。内网记录、上游分组、缓存参数按前面讲的方法填进去。写完用dnsmasq --test做语法检查这个命令会告诉你哪一行有问题比直接重启看日志快得多。第四步启动服务并设置开机自启。启动后立刻用ss -lunp | grep :53确认端口在监听且监听地址是你期望的内网地址不是0.0.0.0。第五步本机验证。在 DNS 服务器上用dig 127.0.0.1 nas.home.lan查内网域名用dig 127.0.0.1 一个常用域名查外网域名看是否都能返回。再查一个不存在的域名确认返回 NXDOMAIN 而不是超时。第六步客户端验证。把一台客户端的 DNS 手动指向192.168.10.10重复上面的查询。如果本机通、客户端不通问题基本在防火墙或监听地址上。4.2 关键参数的计算与选择过程缓存大小不是拍脑袋定的。假设内网有 50 台设备每台平均访问 30 个不同域名那就是 1500 条记录。考虑到 TTL 过期和重复缓存设成 2000 到 3000 比较稳妥。每条缓存记录占用的内存很小2000 条也就几 MB完全不用担心。neg-ttl的设置要看你的使用习惯。如果内网经常有拼写错误的域名查询设短一点30 到 60 秒能更快纠正如果查询比较稳定设长一点减少上游压力。我一般用 60 秒。上游数量上我建议至少两个最多四个。太少了没有冗余太多了轮询反而增加不确定性。两个本地/运营商 DNS 加一个公共 DNS 是比较平衡的组合。日志方面log-queries会记录每一次查询排查问题时非常有用但长期开启日志量很大。我的做法是平时关掉出问题时临时开排查完再关。log-facility可以指定日志文件路径方便单独分析。4.3 验证与压测的实操记录验证分三层功能验证、性能验证、异常验证。功能验证就是前面说的 dig 查询覆盖内网域名、外网域名、不存在域名、通配域名四类。每一类都要确认返回符合预期。性能验证可以用dig循环查询看平均耗时或者用dnsperf这类工具做批量压测。我实测一台 1 核 1G 的虚拟机跑 dnsmasq缓存命中情况下 QPS 能到几千内网几十上百台设备完全无压力。首次查询未命中缓存的耗时取决于上游通常几十毫秒。异常验证最容易被忽略但最重要。要测的场景包括上游 DNS 挂掉一个时是否还能解析、查询一个超长域名是否正常返回、并发大量查询时是否丢包、服务器重启后配置是否自动生效。这些场景平时不出问题一出就是大问题。注意压测时不要对着生产上游猛打容易触发上游限流甚至被封。压测缓存命中用本地域名即可测转发能力时控制好速率。5. 常见问题与排查技巧实录5.1 服务起不来与端口占用排查这是新手遇到最多的第一道坎。现象是systemctl start dnsmasq失败日志里写着failed to create listening socket for port 53: Address already in use。排查思路很固定先用ss -lunp | grep :53看谁占着端口。十有八九是 systemd-resolved。处理方式是编辑它的配置把DNSStubListeneryes改成no然后重启该服务。这样它不再监听 53但其他功能保留。如果确认不需要它直接停用也行。还有一种情况是配置里监听了不存在的网卡名dnsmasq 也会起不来。用ip addr确认网卡名拼写正确。日志里会明确写“unknown interface”对着改就行。5.2 解析失败的分层定位法解析失败不要瞎猜按链路一层层查。我总结的顺序是本机 → 服务 → 上游 → 客户端。先在本机dig 127.0.0.1 域名。如果本机都不通问题在服务本身看日志、看配置、看端口。如果本机通换客户端dig 服务器IP 域名。客户端不通查防火墙和监听地址。如果客户端也通但某个特定域名不通那就是上游或分流规则的问题用dig 上游IP 域名直接问上游验证。这个分层法能快速把问题范围缩小到一段避免在无关的地方浪费时间。我见过有人客户端解析不了结果查了半天 dnsmasq 配置最后发现是客户端自己还配着旧的 DNS 地址。5.3 缓存不生效与解析变慢的处理有时候明明配了缓存第二次查询还是慢。原因通常是上游返回的 TTL 太短或者查询根本没走缓存。先确认查询是否命中缓存开启log-queries后日志里命中缓存的查询会标注来源。如果没命中检查是不是查询的域名带了随机子域有些应用会这样这种天然无法缓存。如果 TTL 太短dnsmasq 有个min-cache-ttl参数可以设置缓存的最小 TTL强制把短 TTL 拉长。但要谨慎设太大可能导致域名切换 IP 后长时间解析到旧地址。我一般设成 60 秒平衡缓存效果和更新及时性。解析变慢还有一个常见原因是上游本身慢。用dig 上游IP 域名测一下上游响应时间如果上游就慢换上游比调本地参数有用得多。5.4 常见问题速查表现象可能原因排查动作服务启动失败53 端口被占用ss -lunp | grep :53找占用进程服务启动失败网卡名写错ip addr核对接口名本机通客户端不通防火墙拦截检查 53 端口 TCP/UDP 规则本机通客户端不通只监听了 127.0.0.1改listen-address为内网地址特定域名解析不了分流规则写错检查server/域名/规则缓存不生效TTL 太短查看日志确认是否命中考虑min-cache-ttl解析时快时慢上游不稳定直接 dig 上游测响应时间内网域名泄露到上游缺少内网分流加server/内网后缀/本机IP5.5 几个踩过坑才懂的实操心得第一个心得改配置前先备份改完先--test。dnsmasq 的配置错误有时候不会在启动时报错而是静默忽略某一行导致你以为配了其实没生效。--test能抓出大部分语法问题。第二个心得日志是你的朋友但别一直开着。log-queries排查时开平时关。长期开着不仅占磁盘高并发时还会拖慢服务。第三个心得内网域名后缀别用真实公网后缀。有人图省事用.com或.local做内网后缀前者会和真实域名冲突后者和 mDNS 冲突。用.lan、.home、.internal这类保留或自定义后缀最稳妥。第四个心得给 DNS 服务器配个静态 IP。如果它自己靠 DHCP 拿地址地址一变所有客户端的 DNS 配置全失效那场面很尴尬。第五个心得做好配置的版本管理。把/etc/dnsmasq.d/纳入 git 或定期备份换机器时直接拉下来就能用比重新配一遍快得多。6. 进阶玩法与扩展方向6.1 广告与恶意域名拦截dnsmasq 做域名拦截非常简单用address/广告域名/0.0.0.0或address/广告域名/#就能把域名解析到空地址或直接返回空。#的写法更干净客户端会收到“无此记录”不会去连 0.0.0.0。维护拦截列表的实用做法是找现成的域名列表用脚本转换成 dnsmasq 的address格式定期更新。转换逻辑很简单每行一个域名输出address/域名/#。写个几行的脚本就能自动化。要注意的是拦截列表别贪多。列表越大每次查询要匹配的规则越多性能会下降。而且误拦正常域名的情况也会增加。我的建议是只拦确认有问题的定期清理失效规则。6.2 和 DHCP 联动实现自动下发如果 dnsmasq 同时管 DHCP客户端连上网络后会自动拿到 DNS 地址完全不用手动配。配置里加dhcp-range192.168.10.100,192.168.10.200,12h定义地址池加dhcp-optionoption:dns-server,192.168.10.10指定下发的 DNS。联动的好处是统一管理。新设备接入自动生效改 DNS 地址只改一处。dnsmasq 还会把 DHCP 租约里的主机名自动注册成 DNS 记录客户端用主机名就能互相访问非常方便。提示如果网络里已经有别的 DHCP 服务器别让 dnsmasq 再接管 DHCP否则会冲突。这种情况只让它做 DNS 即可。6.3 高可用与多台 DNS 的配合单台 DNS 是单点挂了整个内网解析就瘫。做高可用有两个思路一是部署两台 dnsmasq客户端配两个 DNS 地址主挂了自动切备二是用 keepalived 做 VIP两台共享一个虚拟地址客户端只配 VIP。对大多数内网场景第一种就够了配置简单成本低。两台机器配置保持一致用同一份配置文件的副本定期同步即可。客户端下发两个 DNS 地址主备自动切换。要注意的是两台 DNS 的缓存是独立的切换后会有短暂的缓存未命中解析稍慢但功能不受影响。这是可接受的代价。6.4 监控与日常维护要点DNS 是基础设施平时没人注意出问题就是全网瘫痪。所以基本的监控要有。最简单的做法是写个定时脚本每隔几分钟 dig 一个已知域名失败就告警。进阶一点可以采集查询量、缓存命中率、上游响应时间这些指标。日常维护主要是三件事定期更新拦截列表、定期检查日志有无异常查询、定期备份配置。这三件事花不了多少时间但能避免大部分突发问题。我在实际运维中的体会是DNS 服务的稳定性 90% 取决于前期规划是否清晰。监听地址、上游分组、内网后缀、缓存策略这几件事在部署时想明白后面基本不用怎么动。反过来如果一开始图快随便配后面每加一个需求都要推倒重来那才是真的累。所以宁可前期多花半小时把架构理清楚也别急着敲命令。