这次博客部署后,我把 Cloudflare Pages 提供的地址绑定成了自定义域名:

https://field-notes-blog.pages.dev
https://blog.labnote.top

前者可以正常打开,后者却一直显示 404。最开始很容易怀疑 DNS 或 SSL,但最后真正的问题其实出在 Pages 的生产分支。

先不要猜,先判断错误发生在哪一层

我把访问链路拆成四层:

  1. DNS 是否把域名解析到 Cloudflare?
  2. HTTPS 证书是否正常?
  3. 自定义域名是否绑定到了正确的 Pages 项目?
  4. 这个项目的生产分支上是否真的有网站内容?

这样做的好处是,每一步都有一个可以验证的证据,不会把所有问题都归结成“Cloudflare 配置错了”。

DNS 正常,不代表网站一定正常

查询 blog.labnote.top 的 DNS,得到的是 Cloudflare 的 IP:

104.21.24.130
172.67.218.238

这说明域名已经到达 Cloudflare。接着用 HTTPS 访问,返回的是:

HTTP/1.1 404 Not Found
Server: cloudflare

这个结果很关键。它说明 TLS 握手已经成功,请求也已经进入 Cloudflare。问题不是证书,也不是域名没有解析,而是 Cloudflare 没找到这个域名对应的网站内容。

找到 Pages 项目和生产分支

查看 Pages 项目后,发现项目实际名称是:

blog-labnote

它绑定了两个域名:

field-notes-blog.pages.dev
blog.labnote.top

项目名称和 pages.dev 域名不一定相同,这一点容易让人误以为自己操作了两个项目。

接着查看部署记录,发现项目里同时存在两个分支:

main
master

之前手动发布博客时,内容被部署到了 main。但是这个 Pages 项目的生产分支是 master,而自定义域名跟随的是生产分支。

结果就变成了:

field-notes-blog.pages.dev -> main -> 有博客内容
blog.labnote.top            -> master -> 空部署 -> 404

这也解释了为什么两个域名的表现不一样。

修复方式

解决方法不是重新改 DNS,而是把同一份构建产物发布到正确的生产分支:

npm run build
npx wrangler pages deploy dist \
  --project-name blog-labnote \
  --branch master

发布完成后,再访问自定义域名,返回 HTTP 200,首页和文章内容都恢复正常。

Cloudflare Pages 的自定义子域名需要在 Pages 项目中完成绑定,并配置指向 Pages 域名的 CNAME。只添加 DNS 记录而没有在 Pages 中关联项目,也可能导致域名无法正常工作。详见 Cloudflare Pages 自定义域名文档

这次学到的排错顺序

以后遇到类似问题,我会按这个顺序检查:

  1. dig 检查 DNS 是否解析到了正确的平台。
  2. curl -I 区分 TLS 错误、重定向、404 和 5xx。
  3. 在 Pages 中确认自定义域名的状态是否为 active。
  4. 查看项目真正的名称和生产分支。
  5. 分别访问生产域名和每个部署的预览地址,比较它们对应的内容。
  6. 确认构建产物被发布到了自定义域名实际使用的分支。

最后一个提醒

一个 Pages 项目同时使用 Git 集成和 Wrangler 手动部署时,要特别注意分支。Git 可能从 master 自动发布,而本地命令却把文件上传到了 main,两套流程就会产生不同版本。

更稳妥的做法是统一发布方式。如果生产分支是 master,以后就始终使用:

npm run build
npx wrangler pages deploy dist \
  --project-name blog-labnote \
  --branch master

域名只是入口,分支才决定入口最终看到什么内容。