Note Whitebook

站点交接白皮书 · 2026-11-14 PassNAT HTTPS 排障实录

一次 HTTPS 隧道排障的完整复盘:cag.odn.cc 打不开并非证书或配置问题,而是节点 184 的 443 被平台侧屏蔽,换节点到 183 后又被 Windows 优先使用的 IPv6 DNS fe80::1 拖回旧 IP。含端口矩阵诊断法、--resolve/DoH 验证手法、IPv6 DNS 检查与还原命令、五步定位法与一页速查卡。

这是一篇打了白皮书标记的笔记:按笔记管理(版本、权限都在笔记体系里),但用白皮书版式阅读与编辑。

笔记型来自笔记 · 公开笔记 v1

站点交接白皮书 · 2026-11-14 PassNAT HTTPS 排障实录

一句话结论:cag.odn.cc 打不开,既不是证书问题,也不是隧道配置写错,而是两层「地址」问题叠加——先是节点 114.66.28.184 的 443 被平台侧屏蔽,换节点后又被 Windows 的 IPv6 DNS fe80::1 拖回旧 IP。两处都清掉后,HTTPS 稳定 200、0.42 秒响应。

这份文档写给谁:下一次遇到「隧道显示正常但网页打不开」的自己,以及任何接手这台机器的人。全部结论都有实测数据支撑,命令可直接复制。


零、五分钟速览

维度内容
症状https://cag.odn.cc/notes/ 连接超时;http://114.66.28.184:15682/notes/ 却正常
误判 1以为 localAddr = 127.0.0.1:3000 填错了(站点在 3102)—— 实际门户 3000 反代 /notes,填 3000 才对
误判 2以为证书有问题 —— 实际 SAN、有效期、配对、链路四项全对
真因 1节点 114.66.28.184 的 443 端口 TCP 层不可达(同节点 80/8500/15682 全通)
真因 2Windows 优先使用 IPv6 DNS fe80::1,该路由器 DNS 仍返回旧 IP 184,改 IPv4 DNS 无效
处置控制台把 HTTPS 隧道切到 114.66.28.183;本机 IPv6 DNS 换成 2400:3200::1
结果解析 183,curl 200 / 0.42s,真实浏览器全绿(0 报错、0 混合内容)
耗时从报障到彻底解决约 1 小时,其中 3 次是因为「只验证了一半」而误判

一、时间线:这一天到底曲折在哪

时间事件当时的判断事后看
前一日 16:06申请 Let's Encrypt 证书,落到 C:\certs\以为完事证书确实没问题,但它不是瓶颈
前一日 16:15–16:53建了多条测试隧道(183 / 96.65 / 14.91 节点,cag1.odn.cc 等)试探节点留下 5 份 toml 噪音,后期全靠它们做对照实验
前一日晚提交工单:HTTPS 隧道不通怀疑平台没开 HTTPS平台回复「青春版支持 HTTPS」,方向正确但没指出端口问题
今日 10:13工单回复:走节点 443、不要带端口、必须 https认为配置一切就绪这条信息是重要线索,但漏了「节点 443 可能没开」
10:15–10:20逐项体检配置、证书、frpc、DNS全部正常,陷入困惑缺了「端口矩阵」这一步,看到 443 超时就该立刻做
10:21用户控制台把节点从 184 切到 183客户端重新下发配置关键一步,但此时 DNS 还没跟
10:22用 --resolve 强制指向 183200 / 1.37s证明应用与证书全对,问题被压缩到「解析」一个变量
10:23权威 DNS 切到 183,TTL 603以为马上好公共 DNS 陆续生效,114DNS 慢了 8 分钟
10:26–10:29死等 114DNS以为只是缓存114DNS 确实 10:29 才切
10:40用户改完 IPv4 DNS、等够了,仍不通一度怀疑平台又出问题真凶:IPv6 DNS fe80::1 从未被改过
10:42换掉 IPv6 DNS,清缓存立即 200 / 0.42s收工

最贵的一课:10:22 就已经证明「链路 + 应用 + 证书」全对,剩下的只有 DNS。但因为只查了 IPv4 那一半,又白等了 18 分钟。


二、目标与环境速查

需求:让 cag.odn.cc 以 HTTPS 承载笔记站(/notes/),走 PassNAT 青春版隧道;http://114.66.28.184:15682 作为备用入口。

项值
站点入口门户 server.js(计划任务 KaoyanPortal,端口 3000)→ 反代 /notes → Next 笔记站(KaoyanNotes,端口 3102)
隧道类型https + https2http 插件(frp 原生能力,HTTPS 在边缘终结,回源走 HTTP)
隧道节点114.66.28.183:8500(原 184,已废弃)
隧道配置文件C:\Users\cag\AppData\Roaming\com.passnat.client\frpc\18093f6f7432318b.toml
客户端C:\Users\cag\AppData\Local\PassNAT\frpc.exe(v0.71.0)+ passnat-client-v2.exe
证书目录C:\certs\cag.odn.cc-chain.pem、C:\certs\cag.odn.cc-key.pem
域名托管odn.cc 的 NS 在阿里云(vip1/vip2.alidns.com),由 PassNAT 平台代管记录
备用 HTTPShttps://cag.quest(Cloudflare 隧道,独立链路)

三、第一步:先证明「不是我们的错」

排障的纪律是先把不变量钉死,把变量一个个减掉。配置层做了四项体检,全部通过。

3.1 隧道配置(关键字段)

serverAddr = "114.66.28.183"
serverPort = 8500
metadatas.id = "udojmM76fS"

[[proxies]]
name = "91a7bece-0780-4527-aaa4-a08852686f56"
type = "https"
customDomains = ["cag.odn.cc"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:3000"
hostHeaderRewrite = "127.0.0.1"
crtPath = "C:\\certs\\cag.odn.cc-chain.pem"
keyPath = "C:\\certs\\cag.odn.cc-key.pem"

三点必须同时满足,缺一不可:

  1. type = "https" + https2http 插件(不是裸 tcp)。
  2. customDomains 必须与访问域名完全一致,不能带端口、不能带路径。
  3. Windows 下证书路径的 \ 必须写成 \\,否则 frpc 报 error unmarshaling json,隧道静默不起来。

3.2 证书四项核对

检查项命令结果
SAN 是否含域名openssl x509 -in crt.pem -noout -ext subjectAltNameDNS:cag.odn.cc ✅
有效期openssl x509 -in crt.pem -noout -dates2026-11-13 → 2027-02-11 ✅
私钥是否配对比对 x509 -pubkey 与 rsa -pubout 的 sha256一致 ✅
证书链是否完整grep -c "BEGIN CERTIFICATE" chain.pem3 张(叶子 + 中间 + 根)✅

要点:PassNAT 的证书不上传平台,只存在运行客户端的机器上,控制台里填的是绝对路径。这是它和 CDN 厂商最大的区别,也是最容易误解的地方。

3.3 客户端与长连接

Get-CimInstance Win32_Process | ? { $_.Name -match 'frpc|passnat' } | Select ProcessId,CommandLine
Get-NetTCPConnection | ? OwningProcess -in 36812,37720

两条 frpc 进程分别挂着 4e57717e...(tcp→3000)与 18093f6f...(https→cag.odn.cc),都到 114.66.28.184:8500 处于 Established。配置语法另用 frpc.exe verify -c xxx.toml 验证,返回 syntax is ok。

结论:客户端在线、配置合法、证书齐全。 问题不在本机配置。


四、第一个坑:差点把对的改成错的

隧道里 localAddr 写的是 127.0.0.1:3000,而笔记站明明跑在 3102。第一反应是「填错了,改成 3102」。

动手前先量了一下:

curl -s -o /dev/null -w "%{http_code} %{size_download}\n" http://127.0.0.1:3000/notes/   # 200 66057
curl -s -o /dev/null -w "%{http_code} %{size_download}\n" http://127.0.0.1:3102/notes/   # 200 66057

两边返回的字节数完全相同,说明门户 3000 已经把 /notes 反代到 3102。localAddr = 3000 是正确的,改成 3102 反而会绕过门户的鉴权注入与静态资源处理。

教训:看到「端口不一致」不要先改,先量。一个 curl 的字节数对比,省掉一次线上故障。


五、第二个坑(真凶一):443 端口被节点屏蔽

配置全对、客户端在线、页面本地正常,那么问题只能出在「路上」。于是做端口矩阵:

目标结果含义
114.66.28.184:443TIMEOUT❌ 本节主角
114.66.28.184:80OPEN节点活着
114.66.28.184:8500OPENfrps 控制端口正常
114.66.28.184:15682OPEN备用 HTTP 隧道正常
114.66.28.183:443OPEN同机房另一节点正常
110.42.96.65:443OPEN正常
103.40.14.91:443OPEN正常
本机访问 baidu.com:443200 / 0.5s本机出站 443 正常

同节点其他端口全通、唯独 443 超时;同机房其他节点 443 全通。 这不是本机防火墙(否则百度也不通),不是配置(否则 15682 也不通),只能是该节点的 443 未放行 / VIP 未挂载。

再用外部视角复核一次:通过本机代理(另一网络出口)发 CONNECT cag.odn.cc:443,同样返回 502 Bad Gateway——换出口也不通,锁定目标侧。

诊断口诀:一个端口不通时,先问三个问题——同 IP 其他端口通吗?同角色其他 IP 通吗?换个出口还通吗?三问之后,责任方基本就定了。


六、修复一:控制台换节点 184 → 183

操作:PassNAT 控制台 → 隧道管理 → 该 HTTPS 隧道 → 节点/线路改为 114.66.28.183 → 保存 → 重启客户端。

生效标志:本机 toml 被重新下发(serverAddr 从 184 变 183,文件 mtime 更新到 10:21),frpc 自动重连。

此时出现的一个假象:控制台里所有节点的「延迟」永远显示 N/A,让人以为一个都不能用。这是平台测速显示的问题,与实际连通性无关——实测 183 页面 0.42 秒,比 Cloudflare 的 cag.quest(1.67 秒)还快。判断节点可用性,永远以「TCP 端口探活 + 真实页面响应」为准,不要看那个数字。

验证手法(DNS 还没更新时特别有用):

curl -sS --resolve cag.odn.cc:443:114.66.28.183 \
     -o /dev/null -w "%{http_code} %{time_total}s\n" https://cag.odn.cc/notes/
# 200 1.37s

--resolve 绕过 DNS,直接把「域名 + SNI + 指定 IP」拼在一起打,能通就证明:链路、证书、https2http、hostHeaderRewrite、后端应用,全部正确。剩下的变量只有解析。


七、第三个坑(真凶二):DNS 的三层缓存

7.1 权威记录与 TTL

curl -s "https://dns.alidns.com/resolve?name=cag.odn.cc&type=A"
# {"Answer":[{"TTL":525,"type":1,"data":"114.66.28.183"}]}

权威已指向 183,TTL 603 秒(10 分钟)。这个数字决定了「最坏情况下要等多久」,也决定了排查时该不该怀疑 DNS。

7.2 公共 DNS 逐个点名

DNS返回备注
223.5.5.5(阿里)183快
119.29.29.29(DNSPod)183快
180.76.76.76(百度)183快
8.8.8.8(Google)183快
1.1.1.1(Cloudflare)183快
114.114.114.11418410:29 才切换,慢了约 8 分钟
本机默认(路由器 fe80::1)184真正的拦路虎

反直觉点:DNS 变更不是「一改全改」。权威改了,各地递归缓存各自倒计时。「我等了十分钟」不等于「缓存都过期了」,必须逐个 DNS 点名验证。

7.3 最阴的一层:IPv6 DNS fe80::1

用户已经把网卡 IPv4 DNS 改成 119.29.29.29 / 223.5.5.5,也等足了时间,依然超时。这时用一条命令看真相:

Get-DnsClientServerAddress | ? { $_.ServerAddresses.Count -gt 0 } |
  Select InterfaceAlias, AddressFamily, @{n='DNS';e={$_.ServerAddresses -join ', '}}

输出暴露了问题:

以太网   2 (IPv4)   119.29.29.29, 223.5.5.5     ← 用户改的
以太网  23 (IPv6)   fe80::1, fe80::1            ← 从没被改过

Windows 的解析顺序里 IPv6 DNS 优先,而 fe80::1 是路由器通过 RA 下发的地址,它(或其上游)还缓存着旧 IP。验证一下:

nslookup cag.odn.cc fe80::1        # → 114.66.28.184  (旧)
nslookup cag.odn.cc 119.29.29.29   # → 114.66.28.183  (新)

两条查询走的是同一台机器、同一个域名,结果却不同。 这就解释了一切:改 IPv4 DNS 只是改了一半,系统压根没在用那一半。

教训:任何「改 DNS」的操作,必须同时确认 IPv4 与 IPv6 两个 AddressFamily。只改一半,等于没改,而且会让人误以为「DNS 生效了但网站还是坏的」,把排查引向完全错误的方向。


八、修复二:替换 IPv6 DNS

# 备份原值:fe80::1(路由器下发)
netsh interface ipv6 set dnsservers name="以太网" source=static address=2400:3200::1 register=none validate=no
netsh interface ipv6 add dnsservers name="以太网" address=2400:3200:baba::1 index=2 validate=no
Clear-DnsClientCache

还原(如需回到路由器下发):

netsh interface ipv6 set dnsservers name="以太网" source=dhcp

结果:

系统解析:cag.odn.cc → 114.66.28.183
curl     :200  0.42s

九、验收:纯净环境,零强制解析

最终验收不使用任何 --resolve、不注入 host 规则,完全依赖系统 DNS,模拟真实用户:

项目结果
系统解析cag.odn.cc → 114.66.28.183 ✅
首页 /notes/200,首字节 0.42s,浏览器完整加载 1.69s
笔记详情200,渲染 6 个表格,正文 8551 字,0 破图
表格库 /notes/sheets/200
收藏 /notes/favorites/200
安全上下文window.isSecureContext === true,协议 https:
混合内容0 条(页面内无 http:// 资源引用)
控制台错误0 条
证书校验浏览器未用 -k 也通过(域名匹配 + 链可信)

附注:/notes/login 返回 404 属正常——登录页在门户 /login(200),笔记站本身不设登录路由。验收时别把它当成故障。


十、可复用的排障手册

10.1 五步定位法(按顺序,不要跳)

  1. 解析:nslookup 域名 + 逐个公共 DNS 点名 + IPv4/IPv6 都要看。
  2. 端口:目标 IP 的 443 是否 TCP 可达;同 IP 其他端口、同角色其他 IP 做对照。
  3. 隧道配置:type、customDomains、localAddr、证书路径(\\ 转义)。
  4. 证书:SAN、有效期、公私钥配对、链完整性。
  5. 应用:--resolve 强制打通后看页面,确认反代与静态资源。

10.2 六条命令(照抄即可)

# 1 端口探活(不用装 nc)
timeout 5 bash -c 'cat < /dev/null > /dev/tcp/1.2.3.4/443' && echo OPEN || echo TIMEOUT

# 2 强制域名到指定 IP(绕过 DNS,验证链路与证书)
curl -sS --resolve example.com:443:1.2.3.4 -o /dev/null -w "%{http_code}\n" https://example.com/

# 3 用 DoH 绕过一切本地缓存
curl -sS --doh-url https://dns.alidns.com/dns-query -o /dev/null -w "%{http_code}\n" https://example.com/

# 4 指定 DNS 服务器查询
nslookup example.com 223.5.5.5

# 5 隧道配置语法校验
frpc.exe verify -c C:\path\to\tunnel.toml

# 6 看域名的权威 TTL(决定要等多久)
curl -s "https://dns.alidns.com/resolve?name=example.com&type=A"
# 7 网卡 DNS 全量(务必区分 AddressFamily)
Get-DnsClientServerAddress | ? { $_.ServerAddresses.Count -gt 0 } |
  Select InterfaceAlias, AddressFamily, @{n='DNS';e={$_.ServerAddresses -join ', '}}

10.3 四个反直觉结论

  1. 「节点延迟 N/A」不代表不可用——平台测速显示问题,实测 0.42 秒。判断可用性只看端口探活与页面响应。
  2. 改了 IPv4 DNS 不等于改了 DNS——IPv6 DNS 优先级更高,且常由路由器 RA 静默下发,极易漏改。
  3. 443 通不代表站点通——还需 https2http 插件、hostHeaderRewrite、证书路径转义、后端端口四件事同时正确。
  4. --resolve 能通就是好消息——它一次性排除了链路、证书、反代、应用四层,把问题精确压缩到「解析」。

10.4 三个「不要」

  • 不要看到端口不一致就直接改配置(先 curl 比字节数,可能上游本来就反代)。
  • 不要用「我等了十分钟」当作缓存已过期的证据(逐个 DNS 点名)。
  • 不要在控制台测速数字上纠结(用真机探活)。

十一、遗留与维护

事项说明建议动作
证书续期当前证书 2027-02-11 到期续期后替换 C:\certs\ 下 chain 与 key 两个文件,重启 PassNAT 客户端即可,无需改控制台
184 节点 443该节点 443 仍不可达若日后需回迁,先回工单要求开放 443,或直接留在 183
历史测试隧道目录里有 5 份 toml(183/96.65/14.91,cag1.odn.cc 等)cag1.odn.cc 已无解析,属废弃实验;可择机在控制台删除,避免日后误判
IPv6 DNS已改为阿里公共 DNS需要恢复路由器下发:netsh interface ipv6 set dnsservers name="以太网" source=dhcp
双 HTTPS 入口cag.quest(CF,1.67s)与 cag.odn.cc(PassNAT,0.42s)并存两者独立链路,可互为备份;cag.odn.cc 目前更快
备用 HTTP 入口http://114.66.28.184:15682仅在 HTTPS 故障时作为临时通道,注意明文传输

十二、一页速查卡

症状:隧道客户端在线、配置校验通过、本地页面正常,但公网 https 超时
     ↓
① nslookup 域名              → 看解析到哪
② 端口矩阵(同 IP 多端口 / 同角色多 IP / 换出口)
     ↓ 443 不通且仅此端口 → 平台侧,换节点
③ 控制台换节点 → 客户端重新下发 toml → --resolve 强制验证
     ↓ 强制能通 = 只剩 DNS
④ 逐个公共 DNS 点名 + 查权威 TTL
     ↓ 公共 DNS 都对了但本机不行
⑤ Get-DnsClientServerAddress  → 看 IPv4 与 IPv6 两行
     ↓ IPv6 还是 fe80::1 → 换成公共 IPv6 DNS
⑥ 清缓存,纯净访问验收

写在最后:这次真正耗时的不是技术,而是「只验证了一半就下结论」。10:22 的 --resolve 已经证明其余全对,如果当时多敲一条 Get-DnsClientServerAddress,后面 18 分钟的等待根本不会发生。排障的效率,取决于你多快把变量收敛到一个。