☰
从零搭建内网DNS服务:dnsmasq与BIND选型、配置与排错实战
2026/10/16 5:42:17 网站建设 项目流程

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配置简单,DHCP+DNS 一体
需要权威解析、对外提供域名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 服务器内网 IP:192.168.10.10
  • 内网网段:192.168.10.0/24
  • 计划使用的内网域名后缀:home.lan(演示用,实际可换成你自己的)
  • 上游 DNS:192.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。如果你只想让内网网卡提供服务,写interface=eth1(换成你的内网网卡名);如果想精确到地址,用listen-address=192.168.10.10。两个都写也可以,dnsmasq 会取并集。千万不要图省事写listen-address=0.0.0.0然后机器又有公网 IP,那等于把解析器敞开给全世界。

上游服务器用server=指定,可以写多条。dnsmasq 默认会轮询所有上游,但更稳的做法是用all-servers让它同时向所有上游发查询取最快返回,或者用strict-order按顺序来。我实测下来,内网有本地网关缓存的情况下,把网关放第一条、公共 DNS 放后面,命中率最高。

缓存参数里最重要的是cache-size。默认 150 对家庭够用,但设备一多、访问域名一杂,缓存频繁淘汰会拖慢解析。我一般设成cache-size=2000,内存占用也就几 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-record=nas.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。处理方式是编辑它的配置,把DNSStubListener=yes改成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=/内网后缀/本机IP

5.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-range=192.168.10.100,192.168.10.200,12h定义地址池,加dhcp-option=option: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% 取决于前期规划是否清晰。监听地址、上游分组、内网后缀、缓存策略这几件事在部署时想明白,后面基本不用怎么动。反过来,如果一开始图快随便配,后面每加一个需求都要推倒重来,那才是真的累。所以宁可前期多花半小时把架构理清楚,也别急着敲命令。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询