2026 年 7 月 31 日,Google Search Console 开始记录 s1oopx.bond 的搜索展示。首页和文章终于出现在搜索结果里,我在电脑上逐个点开,页面、图片和评论区都能正常加载;两天后的中午,我用没有开启代理的手机再次搜索自己的网站,Google 仍然能列出结果,点击后浏览器却直接报网络错误。

最初的困惑来自一个很自然的推理:Google 已经抓到页面,电脑也能访问,网站应该已经正常上线。手机的失败说明,这三个条件其实不在同一层:
能被搜索到不等于页面此刻可用更不等于每一条用户网络都能到达这次排查后来定位到一个很具体的差异:山西本地网络直连域名解析出的两个 Cloudflare IPv4 地址时,一个连续返回 HTTP 200,另一个在 TLS 建立前被重置。页面没有整体失效,Cloudflare Tunnel 和 Nginx 也不是从所有网络都不可用;真正变化的是用户到 Cloudflare 入口之间的路径。
电脑的“正常”,先被系统代理推翻了#
这个站的公开访问链路大致是:
访客 -> Cloudflare 边缘入口 -> Cloudflare Tunnel -> Nginx -> Astro 静态文件电脑长期启用系统代理,因此实际链路多了一段:
电脑浏览器 -> 系统代理 -> 代理出口 -> Cloudflare 边缘入口 -> Tunnel -> Nginx手机没有代理:
手机浏览器 -> 本地运营商 -> Cloudflare 边缘入口 -> Tunnel -> Nginx两条链路从 Cloudflare 之后几乎相同,差别集中在前半段。电脑访问成功,只能证明“代理出口到 Cloudflare 的路径可用”;它无法替山西本地运营商证明直连路径也可用。
这也是为什么我没有先去重启 Tunnel 或修改 Nginx。通过代理访问一直能拿到完整页面,说明构建产物、域名路由和后端服务至少在一条外部路径上工作。最值得先验证的,是关闭所有代理后,连接究竟在哪一层失败。
Windows 上除了关闭浏览器扩展,还要防止 curl 继续读取系统代理。后面的测试因此全部显式加入:
--noproxy "*"没有这一步,命令行可能再次从代理出口访问,然后给出一个看似正常、实际上没有测试本地直连的结果。
--noproxy 只能阻止 curl 使用 HTTP、HTTPS 或 SOCKS 等应用层代理。如果系统运行的是 TUN 模式 VPN、透明代理,或者路由器本身接管了流量,数据包仍可能从另一条出口离开;这时还需要检查路由表、出口 IP 和代理软件状态,不能只凭参数名称认定测试已经完全直连。
不要直接访问 IP,要保留域名和 TLS 信息#
当时 DNS 返回两个 IPv4 地址:
104.21.88.226172.67.153.179可以先用系统解析器确认:
Resolve-DnsName s1oopx.bond -Type A拿到地址后,直接打开 https://104.21.88.226/ 并不是有效对照。Cloudflare 的地址由大量域名共享,TLS 握手需要域名作为 SNI,后续 HTTP 请求也需要正确的 Host。直接访问 IP 会引入证书和虚拟主机不匹配,测试的已经不是原来的网站。
curl --resolve 能只替换底层连接地址,同时保留 URL 中的域名:
TCP 连接目标:指定的 Cloudflare IPTLS SNI:s1oopx.bondHTTP Host:s1oopx.bond我用同一个域名、同一个端口和同一个请求路径,分别固定两个地址:
$ips = @("104.21.88.226", "172.67.153.179")
foreach ($ip in $ips) { 1..5 | ForEach-Object { curl.exe --noproxy "*" ` --connect-timeout 5 ` --max-time 12 ` --resolve "s1oopx.bond:443:$ip" ` -sS -o NUL ` -w "ip=$ip http=%{http_code} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}`n" ` https://s1oopx.bond/ }}2026 年 8 月 2 日在山西本地复测时,结果持续表现为:
| Cloudflare 地址 | 五次请求结果 | 失败位置 |
|---|---|---|
104.21.88.226 | 均返回 HTTP 200 | 完成 TCP、TLS 和 HTTP |
172.67.153.179 | 连接被重置 | 未完成 TLS |
这组对照固定了页面、域名、证书、Tunnel 和源站,只改变最前面的连接地址。它把“网站打不开”进一步缩小成“当前网络到两个 Cloudflare 入口地址的可达性不同”。
它仍然没有证明重置由谁造成。故障可能与运营商路径、中间网络设备、目标入口当时的状态或其他网络策略有关。一个地区、一条线路和五次请求,只能描述这次现场,不能外推成“中国大陆都打不开 Cloudflare”。
把一次 HTTPS 请求拆成四层#
页面访问失败时,浏览器通常只显示一句“无法连接”或“网络已重置”。把请求按层拆开,信息会清楚很多:
| 层次 | 要回答的问题 | 这次怎样观察 |
|---|---|---|
| DNS | 域名解析出了什么地址 | Resolve-DnsName |
| TCP | 能否与 443 建立连接 | time_connect、连接错误 |
| TLS | 能否完成带正确 SNI 的握手 | time_appconnect、curl -v |
| HTTP | Cloudflare 是否返回页面或错误码 | http_code、响应头 |
如果 DNS 就失败,继续替换 Cloudflare IP 没有意义;如果 TCP 能连但 TLS 失败,应优先检查路径、SNI 和握手;如果已经收到 Cloudflare 的 4xx 或 5xx,才进入边缘规则、Tunnel 和源站这一侧。
本次失败没有进入 HTTP,因此也不会有可供追踪的页面状态码。只有请求真正到达 Cloudflare 并收到响应后,CF-Ray 等响应头才可能帮助判断被哪个 Cloudflare 位置处理。握手之前就被重置,不能根据一个网站上的“IP 地理位置”标签猜测实际入口。
这种分层还有一个实际好处:以后即使故障表现仍然是“打不开”,也能知道它是否和这次属于同一类。一次是 DNS 异常,另一次是 TLS 重置,再一次是源站 502,修复手段完全不同。
为什么同一个域名会走出不同结果#
Cloudflare 橙云记录不会把真实源站地址直接交给访客,而是返回 Cloudflare 的代理地址。多个网络位置可以同时发布同一段地址,路由系统再根据当前网络关系把连接带到某个可达位置,这就是 Anycast 的基本作用。
因此,一个 Cloudflare IP 不能简单理解成“固定在香港的一台服务器”或“美国节点”。真正被测试的是一组关系:
某个用户网络 -> 某个 Anycast 地址 -> 当时选择的网络路径 -> 某个 Cloudflare 处理位置同一个地址从北京、杭州和山西连接,入口和路径都可能不同;同一地区的移动、联通和电信,也可能走出不同结果。反过来,域名返回的两个地址虽然都属于 Cloudflare,它们在某条线路上的路由和中间处理并不保证完全一致。
Anycast 的目标是让一个全球服务可以从许多位置接收连接,它不是“所有线路体验永远相同”的承诺。BGP 路由更关注可达关系和策略,也不会替网站按每位用户的实时延迟挑出一个永久最快的地址。
所以这次最准确的描述是:
山西本地这条网络在当时可以通过一个 Cloudflare 地址访问网站,对另一个地址的连接则在 TLS 前被重置。
这个描述看起来不如“Cloudflare 被墙”有冲击力,却保留了时间、地点、线路和测试对象,下一次才有可能复现。
Google 收录为什么没有提前暴露问题#
Googlebot 抓取页面时使用的是 Google 自己的网络和抓取节点,不会从我的手机运营商替我访问。它成功获取页面,只能证明 Google 在某个时间通过某条路径拿到了可索引内容。
Search Console 展示的也不是实时可用性监控。抓取、索引、搜索展示和报表更新之间存在时间差,页面今天开始打不开,不会立刻从搜索结果里消失。
这次现场至少有三种不同的“成功”:
| 成功条件 | 当时的证据 | 没有覆盖什么 |
|---|---|---|
| 内容被发现 | Search Console 和搜索结果出现页面 | 当前页面是否仍可请求 |
| 服务端能返回 | 代理出口访问正常 | 国内直连线路 |
| 用户能够打开 | 某条真实用户网络完成 DNS、TLS 和 HTTP | 其他地区与运营商 |
我以前把电脑打开网页当成发布验收,又因为电脑常年使用代理,无意中只验证了同一类出口。Google 的成功抓取进一步强化了错觉,直到手机直连才补上缺失的用户路径。
“优选 IP”有价值,但先别把它叫修复#
发现两个地址结果不同后,很容易想到扫描更多 Cloudflare 地址,找出延迟最低的一个。这样的测试有诊断价值,但“最快”不是第一指标。
对公开网站,更合理的探测顺序是:
- 请求能否稳定完成 TCP、TLS 和 HTTP;
- 一段时间内的成功率是多少;
- 成功样本的 TLS 和总耗时 P95 如何;
- 最后才比较下载速度。
如果要从杭州、北京和山西三个位置复测,三地必须使用同一份候选列表、相同域名、相同次数和相同超时。每个地方各自挑一个最快地址,再计算平均值,比较的不是同一个对象。
三地发现少量候选 ↓合并、去重,形成同一列表 ↓三地用 --resolve 统一复测 ↓记录成功率、失败层次、TLS P95 ↓先看最差线路,再看平均延迟失败请求不能从统计中删除。一个地址四次 40ms、一次完全无法握手,平均延迟看起来仍然漂亮,对真实读者却可能意味着五分之一的打开失败。样本很少时也不必假装 P95 很精确,先记录原始结果和失败次数更诚实。
候选范围同样要克制。为自己的域名排障,先测试 DNS 实际返回的地址和少量明确候选,不需要高频扫描整个 Cloudflare 地址空间。低频、可解释的持续探测,比一次大规模测速更适合判断网站可达性。
为什么测出好地址,普通访客仍然用不上#
curl --resolve 能成功,是因为测试者控制了客户端:连接地址被固定为某个 IP,SNI 与 Host 仍然使用真实域名。以前配置 Xray 等可控客户端时,address 与 serverName/Host 可以分开填写,本质上利用的也是同一个边界。
普通浏览器访客没有这份配置。他们输入域名后,会按照公开 DNS 的回答建立连接。橙云开启时,Cloudflare 决定代理记录返回哪些 Anycast 地址;站长无法把本地扫描出的某个共享地址强制塞给所有浏览器,同时还保留标准的橙云解析行为。
本地 Hosts、curl --resolve 或自定义客户端可以消费“优选”结果,是因为设备受自己控制。把这套能力外推给公开网站,就缺少了最关键的一环:谁负责把连接地址下发给每一个普通访客。
因此,优选 IP 在这篇文章里首先是诊断工具和监控数据。它能证明故障不是页面整体失效,也能帮助受控测试端选择入口;它不会自动改变真实读者的 DNS 和路由。
面向公开访客,真正可选的方案#
如果中国大陆可达性只是“希望尽量好”,先持续测量,不要因一次手机失败就重建整套架构。至少覆盖不同运营商和时间段,判断问题是偶发、区域性,还是已经成为稳定故障。
探针所在网络必须与目标读者相符。部署在云服务器上的北京、上海或广州节点可以观察不同机房路径,却不能自动代表当地家庭宽带和移动数据网络;如果问题只在某个运营商或手机链路出现,就需要该线路上的真实设备、合作测试者或对应网络探针参与复测。
如果大陆稳定访问是明确目标,可选方案会涉及真实的架构成本:
| 方案 | 能解决什么 | 需要承担什么 |
|---|---|---|
| 多地区、运营商持续探测 | 知道故障频率和发生层次 | 只能观察,不能改变访客路径 |
| 独立供应商上的备用站点或备用域名 | 给读者另一条完整路径 | 内容同步、搜索重复和切换提示 |
| DNS only 直连独立 HTTPS 源站 | 绕开 Cloudflare 代理入口 | 暴露源站,需自己处理防护;Tunnel 架构不能直接切换 |
| 多 CDN 或按区域调度 | 降低对单一边缘网络的依赖 | DNS、证书、缓存一致性和故障切换更复杂 |
| 面向大陆的托管或 CDN | 把服务放进更适合目标用户的网络 | 备案、域名接入、成本与合规要求 |
Cloudflare China Network 也属于面向中国大陆的正式产品路径,但它是企业级方案,并涉及备案和接入要求。它与扫描公共 Anycast 地址、再挑一个“优选 IP”不是一回事。
对当前个人站,最小而可靠的下一步是保留 Cloudflare 架构,同时增加不经过日常代理的外部探测;只有监控证明大陆可达性长期不满足目标,再决定是否建设独立备用入口。没有证据就直接上多 CDN,只会把一个网络问题扩展成发布、缓存和证书三个问题。
以后怎样确认网站真的上线了#
这次之后,我把发布验收拆成四层:
构建层:页面、链接和资源能否正确生成服务层:Nginx、Tunnel 和健康检查是否正常边缘层:Cloudflare 是否能返回预期页面用户层:不同网络能否完成 DNS、TCP、TLS 和 HTTP构建成功只能证明文件存在;Tunnel 显示在线只能证明出站连接建立;代理电脑能打开只证明一个出口;Search Console 有数据则只证明 Google 曾经成功处理页面。
真正面向读者的网站,至少需要一条不经过自己日常代理的验证路径。出现故障时,再用 --resolve 固定地址,把 DNS、TCP、TLS 和 HTTP 逐层拆开。这样“打不开”不再是一句模糊抱怨,而是一条可以复现、可以比较、也知道边界在哪里的证据链。
Google 能找到、服务能返回、用户能打开,是三个不同的成功条件。第一次被搜索到值得高兴,但只有第三个条件成立,页面才真正到达读者。
