
平日里,我的工作主要是设计云基础设施、编写微服务,以及大规模部署容器。但上周末,我翻出了那台在抽屉里躺了许久的小巧树莓派。
这台树莓派是我7个月前买的,当时只是模糊地想着“用它做点有意思的事”,但一直没拆封——这算是爱好者的经典误区,总觉得买下硬件,这个项目就完成了九成。如今恰逢周末有空,终于到了动手的时候。
这款信用卡大小的电脑,待机功耗仅3-5瓦,说个直观的对比,比一颗普通LED灯泡的功耗还低。再看看我用的亚马逊云服务器EC2实例,就算只是待机,也在全天候消耗电量,同时掏空我的钱包。
心动的契机
几天前的晚餐时,我刷着YouTube想找些有意思的内容看,就这样一头扎进了树莓派项目的世界。起初只是吃饭时的消遣,很快却变成了由衷的着迷。人们用这些迷你设备实现了各种炫酷的功能:搭建多硬盘的家庭网络存储系统、部署Jellyfin媒体服务器管理影视收藏、自建Nextcloud摆脱iCloud的订阅制。而后,我发现了Pi-hole这个工具。只需搭建自己的DNS服务器,就能让整个网络的设备实现无广告浏览?
随着了解的深入,我又认识了Unbound——一款递归DNS解析器,它能直接向根DNS服务器发起查询,而非将请求转发给谷歌或Cloudflare。这样的方式,能带来更高的隐私性、更强的控制权,也能让我学到更多知识。我骨子里的工程师特质被彻底勾起了。
硬件配置
我选用的是8GB内存版树莓派5。存储方面,我想找比SD卡更可靠、且能为未来项目预留空间的方案。一番研究后我发现,树莓派可以外接M.2 NVMe扩展板,能实现高速、稳定的存储,再合适不过。于是我在eBay上淘了一块256GB的NVMe固态硬盘搭配使用。


初期的搭建步骤十分简单:刷入树莓派系统、设置从NVMe固态硬盘启动(告别读写缓慢的SD卡)、更新软件包,都是常规操作。
技术栈:全容器化部署
我决定在树莓派上部署一套工具,打造一个完整的DNS服务体系:
所有工具均通过Docker Compose实现容器化部署,保证环境的整洁、隔离,且部署过程可复现。完整的编排文件可以在我的GitHub仓库找到:https://github.com/asfandahmed/homelab-self-hosted-server
突发状况:凡事皆非一帆风顺
容器启动一切顺利,Pi-hole的网页管理界面也能正常打开。我在路由器中为树莓派分配了静态IP,并将其设为首选DNS服务器。用手机打开一个网站,成功了!页面上再也没有广告了!

我能顺利访问所有本地服务的管理仪表盘,一切看似完美——但这份顺畅只持续了大约五分钟。
怪事开始发生。
网页有时能瞬间加载,下一秒却突然无法连接;二十秒后,又能正常访问了。Reddit网站会加载成功,接着又超时;苹果的各类服务会访问失败,重试后却又莫名恢复。这感觉就像在玩DNS轮盘赌,毫无规律可言。
查看Pi-hole的日志,显示所有查询均成功执行;Unbound也能正常响应请求,但设备端却会随机收到SERVFAIL(服务器失败)的错误提示。问题究竟出在哪里?
日常生活中,我们上网时一切都顺理成章,DNS解析在毫秒间完成,过程完美又隐蔽,没人会去在意根提示文件或DNSSEC验证链这些东西。
但当你自己搭建一台递归DNS服务器后,这些你从未关注过的细节,就都成了必须弄懂的问题。在翻遍日志、经历了一段漫长且需要极度耐心的故障排查后,我终于找到了问题的症结。
大小写引发的混乱
这个问题的原因让我大跌眼镜。Unbound有一项名为“0x20 encoding”的安全功能,它会随机将DNS查询中的域名大小写打乱(比如把 google.com 变成 GoOgLe.CoM);当服务器返回响应时,Unbound会校验域名的大小写是否与查询时一致,以此降低DNS缓存投毒攻击的风险。
听起来是个很棒的功能,对吧?但问题在于,苹果、抖音等大公司,以及不少内容分发网络(CDN)的DNS服务器存在缺陷,无法正确处理这种大小写随机的查询请求。Unbound会将这类响应判定为“无效”,并返回SERVFAIL错误。
我关闭了这项功能(将配置项 use-caps-for-id 设为 no),所有问题瞬间迎刃而解。颇具讽刺的是,谷歌公共DNS和Cloudflare DNS在我撰写本文时,也并未启用这项功能——原因就是它会导致大量服务器无法正常工作。
DNSSEC带来的意外收获
说实话,在做这个项目前,我对DNSSEC几乎一无所知。在云环境中,这项技术大多被做了抽象处理,用户根本无需接触。但搭建Unbound的过程,逼着我深入弄懂了它的所有细节。
DNSSEC会为DNS记录添加加密签名,构建起从根服务器到各个域名的信任链,能有效防止DNS欺骗和缓存投毒攻击。听起来是不是特别完美?
但现实是,目前只有约5%的域名实际启用了这项技术。苹果、谷歌的大部分服务,以及大型CDN服务商都明确放弃使用DNSSEC,原因主要有三点:
- 大规模部署时,运维操作难度极高;
- 一旦配置出错,整个域名会在全球范围内无法访问;
- HTTPS/TLS协议已经为实际的网络连接提供了安全保障。
当我终于成功配置好DNSSEC,在测试结果中看到 cloudflare.com 显示“安全”时,我激动地挥了下拳头。这只是一个小小的成就,却让我成就感满满。
地理位置的影响
我身处澳大利亚,而大多数根DNS服务器都位于美国和欧洲,我向这些根服务器发起请求的延迟约为113毫秒。
这算大问题吗?其实并不算。首次DNS查询的响应时间约为300-500毫秒(包含DNSSEC验证时间),但缓存后的查询响应时间能控制在20毫秒以内。由于95%的查询都会命中缓存,这种延迟只会偶尔产生影响。
但这也提醒着我,即便身处云时代,地理位置依然重要,物理规律始终无法打破。
我的收获
一直以来,我都在使用云服务商提供的托管服务,而这个项目,让我学到了许多从未接触过的知识:
- 自建服务是一场让人学会谦卑的经历。当Pi-hole出故障时,你不得不真正去弄懂DNS的工作原理。
- 有行业标准,不代表大家都会遵守。DNSSEC虽是行业标准,但互联网上的大部分服务都未启用;DNS域名的大小写规则本有明确规定,但半数权威DNS服务器都未能正确实现。
- 过程本身就是最好的奖励。我本可以直接使用1.1.1.1(Cloudflare的公共DNS),草草了事。但那样的话,我永远不会了解递归解析、DNSSEC验证链这些知识。有时候,看似低效的路径,反而能带来最多的收获。
最终感悟
这台自建DNS服务器,比谷歌或Cloudflare的公共DNS更快吗?缓存查询的情况下,答案是肯定的;但对于我在澳大利亚发起的首次查询,速度反而更慢。它能带来更高的隐私性吗?有,但提升幅度有限。它能实现全网络广告拦截吗?这一点绝对可以。
但这个项目最大的成功,是让我真正弄懂了DNS——是实实在在的理解,而非一知半解。
我是否推荐大家尝试?
如果你只是想简单实现广告拦截,安装一个浏览器插件就足够了。但如果你想学习新知识、动手折腾,甚至愿意在凌晨两点排查为什么 testflight.apple.com 会返回SERVFAIL错误,那么我强烈推荐你搭建自己的DNS服务器。这不仅是运维技能的实践,更是深入理解网络核心原理的绝佳途径。
配置核心避坑点:
- 为Unbound下载最新的官方根提示文件
root.hints。
- 为保证兼容性,可在
unbound.conf 中关闭 use-caps-for-id 功能。
- 在
unbound.conf 中增大缓存空间,提升解析性能。
关于完整的配置步骤和故障排查指南,值得单独写一篇文章详细说明。但如果你正准备开启这段搭建之旅,我想告诉你:你遇到的那些无规律的DNS访问失败,都是成为自建服务爱好者的必经之路。欢迎来到自建服务的世界。
如果你对这类开源实战项目或家庭实验室的搭建感兴趣,欢迎来 云栈社区 交流分享你的经验和遇到的挑战。
