#数字花园
当 .garden 域名遇上国内云
从 525 错误入手,分析 SNI 阻断、Cloudflare 代理失效的根因,以及为什么静态站点最终不需要服务器——附完整排查链路和架构对比。
这个网站最初部署在一台腾讯云轻量云上,前面套了 Cloudflare。上线后浏览器一片空白,CF 返回 525。
525 表示 Cloudflare 和源服务器之间的 TLS 握手失败。常见原因就那几种:证书过期、端口没开、Nginx 的 server block 没配对。但这次的情况是:证书有效,端口开放,本机 curl 返回 200。
看得见,过不去。
问题发生在更前面。
拦截发生在 TLS 握手阶段
.garden 不在工信部 ICP 备案白名单里,无法走备案流程。腾讯云的处置方式是:在网络层检测 TLS Client Hello 中的 SNI,匹配到未备案域名直接 RST 掉 TCP 连接。
这意味着两件事:
- HTTP 请求带
Host: callan.garden→ 腾讯边缘返回302,跳转到备案拦截页 - HTTPS 请求在 TLS 握手阶段,SNI 是
callan.garden→ TCP RST,连接断开
同样的服务器、同样的 Nginx 配置、同样的证书,把 SNI 换成一个已备案域名,握手秒过。排除法指向的结论很明确:Nginx 的 server block 从头到尾没见过这个请求。
SNI 阻断不是应用层的问题。TLS 握手失败发生在 TCP 三次握手之后、HTTP 请求之前——你在服务器里调 Nginx、换证书、重装系统,都碰不到这个东西。
Cloudflare 代理为什么没绕过去
Cloudflare 橙色云朵开启后,链路变成:
用户 → Cloudflare → 源服务器
但 CF 连接源站时,TLS Client Hello 里的 SNI 仍然是你的域名。不然服务器不知道该返回哪个站点的证书。
所以实际链路是:
用户 → Cloudflare → 腾讯边缘(SNI 检测: callan.garden → RST)
三种 SSL 模式——Flexible、Full、Full (Strict)——没有区别。问题不在证书验证方式,在于 TCP 连接根本没有建立。525 在这里不是配置错误,是连接不可达。
「开 CF 代理」和「把网站托管在 CF」是两件事。只要 DNS 仍然指向腾讯云 IP,CF 就必须回源,回源路上 SNI 检测照常生效。
如果保留源服务器,能走通吗
腾讯边缘只拦截标准端口 80 和 443。公网 curl 8443 和 8888 端口能正常返回页面。所以理论上可以:
用户 → CF → Worker/Origin Rules → 非标端口 → 源服务器
试过。链路在技术上是通的,但需要处理 Worker 的证书校验、部署生效机制、路由优先级等问题。即便走通了,每次更新都要走「构建 → 上传服务器 → CF 回源」三层,多出来的环节就是多出来的故障点。
对于静态站点,这种方案属于在不需要服务器的事情上强行保留了一台服务器。
删掉服务器
这个网站是 Astro 构建的静态站点。npm run build 生成的 dist/ 目录只包含 HTML、CSS、JS、图片和音频文件——不需要 Node.js 运行时,不需要数据库。
Cloudflare Pages 直接托管静态文件,提供 HTTPS、全球 CDN、零运维。wrangler pages deploy dist/ 一个命令完成上线。
架构变化:
旧:用户 → DNS(CNAME) → CF → A 记录 → 腾讯云 IP → Nginx → 静态文件
新:用户 → DNS(CNAME: callan.garden → callan-garden.pages.dev) → CF Pages → 静态文件
少三层跳转,少一台服务器,少一个 TLS 握手环节。525 不再出现——不是因为修好了连接,是因为那条连接本身不需要了。
问题的边界
排查这类问题有一个通用思路:确认故障出在哪个层再动手。
Nginx 报错修 Nginx,DNS 错误修 DNS——但如果连接在 TCP 层就被 RST 了,你的 HTTP 服务没有产生任何日志,因为它没有收到任何请求。继续往下层翻配置只会浪费验证时间。
静态站点不需要服务器。把「我有 VPS」当成每个网站的默认前提,会凭空多出一整套需要维护的东西:Nginx、证书自动续期、端口防火墙、系统更新、日志轮转。删掉这些不是因为它们不好,是因为这里不需要。
这篇还会随着后续理解继续修剪。