我的博客怎么跳到百度了?一次 DNS 污染排查,以及 AdGuard Home 真正该打开的开关
先说结论:这次确实是原有 DNS 解析链路出了问题。 HTTP 请求被送到错误地址,再收到跳往百度移动版的
302;同一个域名指定正确的站点地址后,HTTPS 证书验证通过,网页返回200。随后在 AdGuard Home 中启用 DoH 上游,实际访问恢复。但我们没有抓到污染发生的具体一跳,所以不能把责任直接归给某台路由器、某家运营商,也不能把“网站跳转”全部诊断成 DNS 污染。本文把已验证的事实、技术推断和操作建议分开讲清楚。
一、没有改过网站,为什么打开后成了百度?
这次故事的起点非常简单:打开自己的博客,地址栏最后却去了百度移动版。第一反应自然是:网站被黑了?域名过期了?静态页面里混进了跳转脚本?还是 DNS 被污染了?
博客使用 Hugo 生成静态页面,托管在 GitHub Pages,公开博客域名通过 CNAME 指向 Pages 的站点名称。平时访问它,就像给一个熟悉的商店打电话:你只记住店名,通讯录替你查号码。
然而,通讯录上的号码错了,并不代表真正的商店关门了。 你打到另一个地方,对方再说“请去隔壁”,就同时出现了两个问题:第一次是找错地址,第二次是错误地址上的服务给出了跳转指令。
图 1:本文原创 SVG。它是解释事故的示意图,不是现场截图。后文的官方资料截图也会明确标注来源。
二、先拆开三个动作:问路、敲门、看证件
把一次网站访问想成去同学家做客,会容易理解得多。
DNS 是问路。 你说出同学的名字,得到一个门牌号。A 记录提供 IPv4 地址,AAAA 记录提供 IPv6 地址;CNAME 像一句“这个名字也叫另一个名字”,还要继续查到最终地址。自定义域名自身看起来没问题,不代表后面的别名解析一定没问题。
HTTP 是敲门之后的对话。 门里的人说“欢迎进来”,可能对应 200;说“临时去那个地方”,就是 302 加上 Location。DNS 返回的是解析结果,它本身不会发送 HTTP 302。实际跳转由浏览器收到的 HTTP 响应触发;脚本跳转和 HTML 刷新则是其他机制,需要另行检查。
HTTPS 还要看证件。 即使门牌号告诉你到了这里,门里的人也要出示能证明“我就是这个域名”的有效证书。证书不匹配时,正确行为是阻止连接。不要为了“先看看网页”把证书检查关掉,那会恰好拆掉识别冒名者的门锁。
图 2:地址错误与重定向是连续发生的两件事。HTTPS 的证书校验可以在请求正常完成前拦住错误身份。

图 3:真实浏览器截图,来源为 MDN:302 Found。302 表示临时重定向,目标由 Location 指定。
三、这次到底查到了什么?一张不泄露地址的证据表
排障时,没有先修改配置,而是分别看原路径、独立解析和指定正确地址后的访问。公开记录中移除了所有完整 IP、设备名称和内部网络信息,只保留足以理解结论的现象。
| 检查 | 实际结果 | 能说明什么 |
|---|---|---|
| 系统 DNS 与两条局域网解析路径 | 返回同一个异常 IPv4 地址 | 错误并非只存在于单个浏览器页面 |
| AAAA 查询 | 正常结果中混入异常 IPv6 记录 | 不能只盯着 IPv4 |
| 原路径 HTTP 请求 | 302 Found,目标为百度移动版 |
直接复现了跳转 |
| 原路径 HTTPS 请求 | 证书域名不匹配 | 到达的端点无法证明自己就是博客 |
| 两家独立 DoH 服务 | 返回一致的 GitHub Pages IPv4 地址集合 | 得到了独立对照结果 |
| 其中一家 DoH 的 AAAA 查询 | 返回正常 Pages IPv6 地址集合 | 原有 IPv6 结果也需要纠正 |
| 保留域名、指定正确地址访问 HTTPS | 证书通过,200,标题为预期博客标题 |
正确站点仍能正常提供内容 |
| 获取正确站点首页内容 | 未发现百度目标字符串或 meta refresh | 所检查首页未提供这种跳转证据 |
| 改用 AdGuard Home DoH 上游 | 用户确认恢复正常 | 完成了实际体验层的验证 |
最后那条用户确认很重要。终端显示 200,不代表手机浏览器已经清掉旧缓存,也不代表另一台设备确实使用了同一个 DNS。配置正确、接口正常和用户能打开页面,是三件有关联但不等价的事。
图 4:多个对照共同支持“原解析链路异常”。它们没有定位到中间哪一台设备改写或缓存了答案。
为什么指定地址时还要保留域名?
因为直接把地址填进浏览器,会改变 HTTP Host 和 TLS 所验证的名称。共享托管服务靠域名分辨你要访问哪个网站,这样测试很容易把正确服务也测成错误。
curl --resolve 可以只替换连接地址,继续使用原域名做 SNI、证书验证和 HTTP 请求。下面是模板,变量值必须来自你的实际检查;不要照抄网上陌生地址:
# BLOG_HOST:你正在排查的公开域名
# VERIFIED_ADDRESS:通过独立可信渠道核对过的地址
# 若使用 IPv6,按 curl 要求为地址加方括号
curl --noproxy '*' --connect-timeout 5 --max-time 20 \
--resolve "${BLOG_HOST}:443:${VERIFIED_ADDRESS}" \
-I "https://${BLOG_HOST}/"
HEAD 请求能快速看响应头,但网站可能对 HEAD 和 GET 有不同处理,最终还要获取页面正文并打开浏览器。--noproxy '*' 用于明确测试直连路径;如果你的正常访问依赖代理,也要把代理路径作为另一组对照,不能混在一起比较。

图 5:真实浏览器截图,来源为 GitHub Pages 自定义域名文档。共享托管下,连接地址和域名身份需要同时正确。
四、为什么换成“知名 DNS”还不行?
这次还有一个很有辨识度的现象:向两家常见公共 DNS 地址发送普通 UDP 查询,依然收到了与原路径相同的异常答案;而对其中一家改用 TCP 查询,得到了正常的 Pages 地址。
这说明,在命令里写了谁的地址,不等于答案一定由谁原封不动地送回来。 中间路径可能存在透明转发、劫持、错误缓存或其他改写行为。这个现象与 DNS 污染或劫持相符,但单靠这些输出,仍然不能判定具体设备和责任主体。
生活中的比喻是:你换了一家商店打电话,但电话线路里一直有人插话。换号码可能没用,保护这段通信才是关键。
TCP 在这次对照中有用,却不因此变成安全协议。传统 DNS over TCP 同样不提供 TLS 那样的机密性和服务端认证,不能把“这一次正常”当作长期防污染保证。
DoH 改变了什么?
DoH 把 DNS 查询和响应装进 HTTPS。与其在街上喊“谁知道这家店在哪里”,不如给已经核验身份的问路处递一个加密信封:路上的人更难读取或修改内容,冒充问路处还必须通过证书验证。
但信封只保护传递过程,不保证收信人永远正确。选择的解析器仍然可以看到查询,也可能配置错误、执行过滤策略或返回不合适的答案。DoH 不等于匿名工具,也不是网站被入侵、权威记录配错或客户端恶意软件的通用修复药。

图 6:真实浏览器截图,来源为 RFC 8484:DNS Queries over HTTPS。标准定义的是 DNS 查询与响应如何映射到 HTTPS 交换。
五、AdGuard Home 有两个“加密方向”,不要打开错开关
这是本次最值得留下来的操作知识:
设备 ── 接入侧 DNS ──> AdGuard Home ── 上游 DNS ──> 递归解析器
第一段是设备向 AdGuard Home 提问。第二段是 AdGuard Home 不知道答案时,向上游提问。本次修复重点是第二段:在 DNS 设置的上游 DNS 服务器中使用 https://…/dns-query 形式的地址。
管理界面的 加密设置通常是在配置 AdGuard Home 自己对外提供 HTTPS、DoH、DoT 等服务,需要考虑证书、监听端口和客户端接入。只在这里打开加密,而第二段继续使用异常的明文上游,问题未必消失。
图 7:两段通信可以分别配置。本次不能把“使用 DoH 上游”误写成“必须给家庭里的每台设备安装证书”。

图 8:真实浏览器截图,来源为 AdGuard Home DNS 加密文档。此页主要说明如何提供加密 DNS 服务,正好帮助区分两个方向。截图采集时官网按浏览器语言显示中文。
六、人工配置:按这六步走,别只点“保存”
第一步:记录旧配置
保存原来的上游、备用上游、Bootstrap、按域名分流规则,以及客户端自定义上游。配置备份只留在自己的私有目录,别上传到公开仓库,也别把整页管理后台截图直接发出去。若使用上游配置文件,应沿用原有配置管理流程。
第二步:设置经过测试的 DoH 上游
本次对照中,阿里和腾讯的加密解析入口可用。对应常用 DoH 配置如下,保存前仍应在你自己的 AdGuard Home 里点击测试:
https://dns.alidns.com/dns-query
https://doh.pub/dns-query
这不是测速排行,也不是保证所有地区都可用。本次其他部分境外加密入口出现连接超时,说明“协议更安全”和“这条网络能连通”要分别验证。可以使用自己的 DoH 服务,只要证书、可达性和解析结果都经过检查。
第三步:理解 Bootstrap,而不是乱填一串地址
DoH 服务自己也是域名。AdGuard Home 第一次连接它之前,往往需要先查出它的地址,Bootstrap 就像“先告诉我问路处在哪里”。保留或填写本地验证可用的引导解析器,不要把引导查询又绕回依赖它启动的服务,造成鸡生蛋、蛋生鸡的死循环。
引导环节得到错误地址时,正常 TLS 校验通常会阻止冒名连接,但服务也可能因此不可用。不要把证书校验关闭当作解决办法。本文不刊载完整数字地址,实际引导地址请从官方资料核对后在私下配置。
第四步:处理备用路径
如果主上游改成 DoH,备用上游却仍然是那条异常明文路径,那么主服务稍有抖动,问题就可能回来。小型个人部署可以清空不需要的备用项,或填写另一个已经验证的加密上游。业务系统则应先评估可用性要求,不能盲目删除既有容灾设计。
第五步:保存、清缓存,再检查 IPv6
清除 AdGuard Home DNS 缓存,也刷新客户端缓存并重启浏览器。Windows 可使用 Clear-DnsClientCache;Ubuntu 在使用 systemd-resolved 时可运行 sudo resolvectl flush-caches;macOS 可运行:
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
这些命令只刷新当前系统相关缓存,不会神奇地清掉所有浏览器、路由器和应用缓存。
确保 DHCP 下发的 DNS 指向预期服务;同时检查 IPv6 的 RA/DHCPv6,以及浏览器“安全 DNS”和 VPN 是否另走一条路。多个 DNS 地址不一定严格按照“主用坏了才用备用”的顺序工作,不要把异常地址留在列表里当作装饰。
图 9:关闭 IPv6 不是默认答案。更好的做法是把两种地址族的解析与客户端路径都检查完整。
第六步:验收真实访问
重新查询 A 和 AAAA,查看 AdGuard Home 查询日志是否收到这台设备的请求、使用了什么上游、是否命中旧缓存。随后使用正常浏览器访问原来的 HTTPS 地址,确认没有证书警告、没有跳往无关页面,正文确实是预期网站。必要时换第二台设备复测。

图 10:真实浏览器截图,来源为 AdGuard Home Configuration。网页设置和配置文件会随版本演进,操作前应核对正在使用的版本。
七、三系统一键脚本:把重复操作交给程序,把结果留给验证
本文提供 完整离线脚本包,包含 Windows 11、Ubuntu 26.04、macOS 26 三种启动脚本,以及共享的 configure_doh.py 核心。也可单独下载:
依赖边界说清楚:需要预先安装 Python 3.10 或更新版本,只用标准库,不需要 pip、云端 Agent、在线脚本托管或其他自动化服务。 macOS 和 Windows 不保证自带 Python,脚本会检查并停止,不会擅自下载运行环境。使用公共 DoH 当然仍然依赖那家解析服务;若要求不使用第三方递归服务,请提供自己的 DoH 入口,但自建递归本身仍有访问权威 DNS 的网络需求,不能宣称“从此完全离线解析互联网”。
脚本适用于已经安装、初始化、可管理的 AdGuard Home,自动完成:API 预检 → 服务端测试候选上游 → 私有备份 → 替换全局上游并清空备用上游 → 读回对比 → 再测上游 → 清缓存。失败时尝试恢复旧值并验证,失败退出码不为零。
它不会安装 AdGuard Home,不修改路由器 DHCP 或系统网卡 DNS,也不覆盖 Bootstrap、客户端专属规则。发现按域名分流或文件管理的上游时会停止,避免破坏现有部署。运行时应避免另一名管理员同时修改配置。Windows 备份目录应使用当前用户独享的 ACL;备份可能含私人解析地址,不能公开。
图 11:脚本的成功标记只表示目标配置已经应用并读回,不代表全网设备已完成迁移。
方法 A:人来执行,程序自动配置
解压脚本包,在所在目录执行对应命令;按提示在本机输入管理 URL、账号、DoH 地址,密码不会回显。管理 API 必须使用证书可信的 HTTPS;只有通过可信 SSH 隧道连接本机回环时才允许 HTTP,不允许关闭 TLS 校验。
# Windows 11:已安装 Python 及 py 启动器
powershell -NoProfile -File .\windows11.ps1 --apply
# Ubuntu 26.04
bash ./ubuntu26.sh --apply
# macOS 26
bash ./macos26.sh --apply
不加 --apply 只做配置读取和候选上游测试,不保存变更。遇到 PowerShell 执行策略限制,应审阅脚本后按本机政策处理,不建议为了运行教程永久放宽系统策略。
方法 B:Agent 自动配置
在私有目录创建 plan.json,结构如下。花括号内容必须替换成真实值,模板不能原样执行,也不要把真实配置提交进 Git:
{
"base_url": "https://{你的管理入口}",
"username": "{管理账号}",
"upstreams": [
"https://dns.alidns.com/dns-query",
"https://doh.pub/dns-query"
]
}
密码单独保存在当前用户独享的文件中。Linux/macOS 设置文件权限为仅当前用户可读写;Windows 使用相应文件 ACL。私有 CA 可用可选字段 ca_file 指定,不得改成忽略证书。随后让本地 Agent 执行:
python3 configure_doh.py --plan plan.json --password-file password.txt
python3 configure_doh.py --plan plan.json --password-file password.txt --apply
Windows 使用 py -3 替换 python3。脚本没有内置任何云端模型依赖;若使用外部 Agent 服务,不要把密码或未脱敏日志放进对话。可以给 Agent 这段任务约束:
只操作指定的 AdGuard Home。先读脚本和计划文件,只返回脱敏摘要;预检成功后应用,保存私有备份。不要修改客户端网络、Bootstrap、分流和文件管理配置,不要输出密码、完整地址或设备名称。检查退出码,随后单独核验 A/AAAA、查询日志、证书和浏览器页面。如果无法操作浏览器,明确报告“配置已应用,端到端验证待完成”。
需要恢复时,从私有备份目录找到本次 JSON,使用同一计划和凭据运行:
python3 configure_doh.py --plan plan.json --password-file password.txt \
--restore "{本次备份文件路径}" --apply
恢复前会检查当前目标字段是否仍等于当时应用的值;如果后来有人改过,脚本拒绝覆盖。恢复旧上游也可能恢复原来的故障,所以它是撤销工具,不是另一种修复。
验证范围:共享核心通过本地模拟 API 的成功、拒绝和回滚测试,Bash 入口经过语法检查及当前 macOS 调用检查;本文没有声称已在真实 Windows 11、Ubuntu 26.04 和三套生产 AdGuard Home 上全部实测。 API 内置上游测试仅证明测试查询成功,不能保证所有域名、所有客户端都正常。
八、Q&A:几个最容易把人带偏的问题
1. 跳到百度,能证明是百度做的吗?
不能。Location 指向哪里,只说明客户端被要求去哪里。错误服务器、拦截设备或其他组件都可以返回这样的目标,目的地址不是责任归属证据。
2. 两家 DNS 的结果不同,就一定是污染?
也不一定。CDN、地域调度、缓存时间和 ECS 都可能产生正常差异。本次判断依赖的是一整组事实:异常地址、错误重定向、证书不匹配,以及保持域名后的有效 HTTPS 对照。不要拿“地址不一样”这一个现象就下结论。
3. HTTPS 不是很安全吗,为什么还有这件事?
这次 HTTP 路径会跳转,HTTPS 路径则因证书不匹配而失败,后者恰恰是在保护用户。HTTPS-first 和 HSTS 可以减少走到明文 HTTP 的机会,但不会自动修好 DNS 地址簿。用户如何输入地址、浏览器的升级策略和既有 HSTS 状态都会影响最终表现。

图 12:真实浏览器截图,来源为 MDN:Strict-Transport-Security。HSTS 约束 HTTPS 访问,不能替代 DNS 排障。
4. 能不能写 hosts 一劳永逸?
可以作为临时对照,但不建议当作长期答案。托管平台可能调整地址、路由或部署。把今天的门牌号永久钉死,明天可能又走错路。正确做法是修复可信解析路径,并根据官方要求维护域名记录。
5. DNSSEC 和 DoH 是不是一回事?
不是。DoH 主要保护客户端与所选解析器之间的传输;DNSSEC 在签名和验证链完整时验证 DNS 数据的来源与完整性。可以把它们分别理解为“密封运输袋”和“文件上的可验证签章”。没有签名的数据不会因为开启验证就自动获得签名,两者也都无法修复网站自身的恶意跳转代码。
6. 为什么我的电脑好了,手机还不好?
先查手机是不是走蜂窝网络、IPv6 下发的另一台解析器,或者浏览器内置的安全 DNS。再查缓存。不要第一步就恢复出厂设置,也不要用“后台全绿”代替设备侧观察。
7. 开了广告过滤,为什么仍然会中招?
广告过滤决定哪些请求被允许或拦截,上游加密决定允许的查询怎样送出去。允许访问的域名仍可能被错误解析。此次解决问题的是改变上游解析路径,不是新增广告规则。
九、这次真正修好的,不只是一个跳转
最后的验收标准很朴素:同一个网址,用正常的浏览器打开,身份验证正常,页面内容正确。经过上游 DoH 配置后,用户确认问题消失,排障闭环才算完成。
图 13:每一层都要有自己的证据。“保存成功”不能替代“页面正确”。
这类故障最容易让人一上来就重装网站、乱改域名记录或关闭安全检查。更省事的方法,是先问三个问题:地址是谁告诉我的?我实际连到了谁?对方有没有证明自己的身份? 把这三件事拆开,很多看起来像灵异事件的跳转,就会变成可以逐项验证的工程问题。
参考资料与配图说明
资料核对与截图采集于 2026 年 9 月 17 日。本文 13 张配图包括 6 张官方网页真实截图和 7 张原创 SVG;没有把排版后的文字伪装成终端截图,也没有把事后截图说成事故发生时的现场录像。引用网页截图用于对应技术点的说明,内容版权属于原作者。
- AdGuard Home:Configuration:上游、引导和配置项说明。
- AdGuard Home:DNS encryption:作为加密 DNS 服务端的配置。
- AdGuard Home OpenAPI:本文脚本使用的 DNS 配置、上游测试、缓存清理接口;部署版本可能与主分支有差异。
- RFC 8484:DoH 协议。
- MDN:302 Found:临时重定向语义。
- MDN:Strict-Transport-Security:HSTS 与证书错误行为。
- GitHub Pages 自定义域名:托管域名与 DNS 配置。
延伸阅读:DNS 的历史、架构与加密防护、GeoIP、CDN 与 HTTP 重定向。Read this article in English。