全部文章
  1. 01 · 把个人内容门户部署到 Cloudflare:可直接照做的完整教程
返回文章

把个人内容门户部署到 Cloudflare:可直接照做的完整教程

基于门户、英语课程和 Astro 博客三项目架构,从本地聚合、Workers Static Assets 发布、自定义域名到验证与回滚,逐步完成上线。

本文目录
  1. 一、先确认真正要部署的目录
  2. 二、按正确顺序生成最终产物
  3. 三、选择 Workers Static Assets
  4. Pages 和 Workers 怎么选
  5. 四、检查静态资源限制
  6. 五、创建 Wrangler 配置
  7. 六、登录账号并执行预检查
  8. 七、第一次部署并验证 workers.dev
  9. 八、接入正式域名
  10. 1. 确认域名已经接入 Cloudflare
  11. 2. 绑定根域名
  12. 3. 先处理可能的冲突
  13. 4. 不要增加博客转发规则
  14. 5. 验证正式域名
  15. 九、发布后的完整检查
  16. 十、常见问题
  17. 页面能打开,但样式全丢了
  18. 首页正常,文章刷新后 404
  19. 门户能打开,但 /blog/ 是 404
  20. 博客显示的是旧文章
  21. 需要手动回滚
  22. 十一、推荐的发布流程
  23. 十二、最终验收清单
  24. 参考资料

这是一篇针对当前项目真实结构编写的部署手册。完成后,个人门户、英语课程和博客将由同一个 Cloudflare 站点提供:

https://idozhuoyong.com/          个人内容门户
https://idozhuoyong.com/english/  英语学习项目
https://idozhuoyong.com/blog/     个人博客

这篇文章记录我把个人内容门户部署到 Cloudflare 的完整过程:为什么这样选择、每一步怎么操作、遇到什么问题,以及最后如何确认它真的可以访问。

一、先确认真正要部署的目录

当前内容由三个独立项目组成:

先在终端设置三个项目共同所在的工作目录。下面是我的目录结构,但不包含本机用户名;如果你的项目放在其他位置,只需要修改这一行:

export PROJECTS_DIR="$HOME/Documents/project"

后续命令应在同一个终端窗口中执行。重新打开终端后,需要再次设置 PROJECTS_DIR

项目 本地目录 构建产物 最终路径
个人内容门户 ${PROJECTS_DIR}/ido-content-portal dist/ /
英语学习 ${PROJECTS_DIR}/english_study dist/ /english/
个人博客 ${PROJECTS_DIR}/ido_blog dist/ /blog/

门户构建脚本会把英语课程和博客的产物复制到自己的发布目录。真正上传到 Cloudflare 的只有:

${PROJECTS_DIR}/ido-content-portal/dist

最终结构应类似:

ido-content-portal/dist/
├── index.html
├── assets/
├── english/
│   └── index.html
├── blog/
│   ├── index.html
│   ├── 404.html
│   ├── _astro/
│   ├── posts/
│   ├── rss.xml
│   └── sitemap-index.xml
└── build-report.json

不要单独上传 ${PROJECTS_DIR}/ido_blog/dist,否则根路径会直接变成博客,门户和英语课程都不会存在。

二、按正确顺序生成最终产物

先构建博客:

cd "$PROJECTS_DIR/ido_blog"
nvm use 24
npm install
npm run build

nvm use 24 会把当前终端切换到 Node.js 24,避免系统默认 Node.js 版本不满足 Astro 的要求。Astro 检查应显示 0 errors0 warnings0 hints,构建末尾应显示 Complete!

Node.js 24 下执行 Astro 检查和构建的成功结果

接着确认博客关键文件:

test -f dist/index.html
test -f dist/404.html
test -f dist/rss.xml
test -f dist/sitemap-index.xml

test -f 用于确认指定路径存在且是普通文件:条件成立时不输出内容,并以状态码 0 结束;文件缺失时同样不会显示提示,但会返回非零状态码。这里四行分别检查博客首页、404 页面、RSS 和站点地图索引是否已经生成。如果需要立即看到结果,可以在执行后运行 echo $?;输出 0 表示上一项检查通过。

再确认英语课程现有产物:

cd "$PROJECTS_DIR/english_study"
test -f dist/index.html
test -f dist/styles.css
test -f dist/app.js

这三行同样使用 test -f 检查英语课程产物,分别确认首页、全局样式和页面脚本存在。三条命令都没有输出且状态码均为 0,才能说明门户聚合所需的英语课程核心文件已经准备好。

最后构建门户,让它复制两个子站:

cd "$PROJECTS_DIR/ido-content-portal"
npm run build
npm run check

构建日志必须出现:

已接入 /english/ 程序员英语闯关
未接入 /flutter/ Flutter 跨平台实战
已接入 /blog/ 个人博客

继续检查最终发布目录:

test -f dist/index.html
test -f dist/english/index.html
test -f dist/blog/index.html
test -f dist/blog/rss.xml
test -f dist/blog/sitemap-index.xml
sed -n '1,120p' dist/build-report.json

sed -n '1,120p' dist/build-report.json 只读取并打印构建报告的前 120 行,不会修改文件;其中 -n 关闭默认逐行输出,1,120p 指定只显示第 1~120 行。用它可以快速核对各内容项目是否成功接入,publishedRoutes 应包含 /english//blog/。每次执行门户的 npm run build 都会重新生成门户 dist/,所以必须先构建博客,再构建门户。

本地预览最终产物:

npm run preview

预览日志可能显示 http://0.0.0.0:4174/,这是服务监听地址,不是要在浏览器中打开的地址。请使用 http://127.0.0.1:4174/ 访问,再依次打开 //english//blog/、一篇博客文章和 /blog/rss.xml。确认页面可直接刷新,Network 面板没有资源 404,博客链接、Canonical 和资源地址都保留 /blog/ 前缀。完成后在终端按 Control + C 停止预览。

三、选择 Workers Static Assets

Cloudflare 目前仍支持 Pages,但官方文档已经明确建议新项目优先使用 Workers。原因不是 Pages 无法托管静态网站,而是 Workers 已经能够覆盖 Pages 的大多数使用场景,并在同一平台上提供更完整的运行时、路由、可观测性和发布能力。当前站点全部由预先生成的 HTML、CSS 和 JavaScript 组成,可以直接使用 Workers Static Assets。从 Pages 迁移到 Workers

Pages 和 Workers 怎么选

对比项 Pages Workers Static Assets
主要定位 面向静态网站和前端项目,Git 自动部署与分支预览开箱即用 Cloudflare 面向新应用的主要平台,统一承载静态资源和 Worker 代码
部署方式 可以连接 Git,也可以通过 Wrangler 或控制台直接上传已有产物 可以使用 Workers Builds 连接 Git,也可以执行 wrangler deploy 上传已有产物
预览与发布 自动分支预览、分支别名和分支控制更成熟 支持预览 URL、版本回滚和渐进式部署,但部分分支能力需要额外配置
动态能力 Pages Functions 提供基于文件的函数路由 原生支持 Worker 运行时、Durable Objects、Cron Triggers、Queues 和更完整的绑定能力
路由与观测 适合独立站点和常规自定义域名 支持非根路径路由、Workers Logs、Logpush、Tail Workers 和 Source Maps
适合场景 单仓库静态站,希望 Git 推送后自动构建并获得分支预览 希望统一静态站与服务端能力,或需要更灵活的路由、观测和后续扩展

两者都能托管当前这份纯静态 dist/,静态资源请求的成本结构也基本一致。Cloudflare 推荐 Workers,主要是因为它已经成为功能更完整的统一应用平台:除了静态资源,还支持渐进式部署、远程开发、更全面的日志与观测,以及 Durable Objects、Cron Triggers、队列和更多绑定。以后增加 API、定时任务、访问控制或请求级逻辑时,不需要再从 Pages 迁移到另一套平台。

Pages 仍然适合以 Git 自动部署和分支预览为核心的单仓库静态站。如果只看“把一份 dist/ 发布出去”,Pages Direct Upload 同样能完成;本项目选择 Workers,并不是因为 Pages 做不到,而是 Workers 符合 Cloudflare 当前的新项目方向,也为门户后续扩展保留了更直接的路径。Cloudflare Pages 迁移指南

这个方案直接上传本地聚合后的 dist/,不要求 Cloudflare 同时访问三个仓库,也不需要为 /blog/ 配置 Origin Rule 或 URL Rewrite。每次部署都会形成版本,后续可以使用预览地址和回滚。

不要只把 ido-content-portal 仓库连接到 Cloudflare Workers Builds 或 Pages Git 集成,然后直接将 npm run build 设置为云端构建命令。Cloudflare 的构建环境只会检出所连接的门户仓库;如果构建脚本没有另外检出其他仓库,就不会自动取得独立仓库中的 english_studyido_blog,门户构建也无法读取它们的 dist/,最终发布产物会缺少 /english//blog/Workers Builds 配置

以后如果改成 Monorepo、Git Submodule,或者让 CI 主动检出三个仓库并下载各自的构建产物,也可以在云端完成聚合。当前教程选择先在本地依次构建三个项目,再通过 Wrangler 上传门户最终的 dist/,是为了先跑通最直接、可检查和可回滚的发布流程。

四、检查静态资源限制

Workers 免费计划的单个版本最多包含 20,000 个静态文件,单个文件最大为 25 MiB。上传前执行:

cd "$PROJECTS_DIR/ido-content-portal"
find dist -type f | wc -l
find dist -type f -size +24M -print
du -sh dist

文件数量应明显少于 20,000,第二条命令不应输出文件。发现异常缓存、源码或超大文件时应先处理,不要直接上传。Cloudflare Workers 限制

五、创建 Wrangler 配置

${PROJECTS_DIR}/ido-content-portal 根目录新建 wrangler.jsonc

{
  "name": "ido-content-portal",
  "compatibility_date": "2026-09-12",
  "workers_dev": true,
  "preview_urls": true,
  "assets": {
    "directory": "./dist/",
    "not_found_handling": "404-page",
    "html_handling": "auto-trailing-slash"
  }
}

这里最重要的是 assets.directory 必须指向门户的 ./dist/404-page 会让不存在的路径返回真正的 404,auto-trailing-slash 与当前 Astro 目录形式的页面一致。不要使用 single-page-application,否则不存在的文章可能返回门户首页和错误的 200静态生成站点与自定义 404

第一次部署先不要加入正式域名。先验证 workers.dev 地址,再通过控制台绑定域名,可以降低误切换 DNS 的风险。

六、登录账号并执行预检查

在门户目录运行:

cd "$PROJECTS_DIR/ido-content-portal"
npx wrangler@latest login
npx wrangler@latest whoami

Wrangler 会通过浏览器完成 OAuth。确认 whoami 显示的账号就是管理 idozhuoyong.com 的账号。如果浏览器登录回调失败,可以改用:

npx wrangler@latest login --device

不要把 OAuth 凭据、API Token 或账号 ID 写入仓库、文章或聊天记录。Wrangler 登录与账号检查

检查当前目录和配置:

test "$(basename "$PWD")" = "ido-content-portal"
test -f wrangler.jsonc
test -f dist/index.html
npx wrangler@latest deploy --dry-run

第一条命令没有输出,表示当前位于门户目录。dry run 应在不创建正式部署的情况下完成配置和资源检查。

七、第一次部署并验证 workers.dev

确认账号、Worker 名称和 dist/ 正确后执行:

npx wrangler@latest deploy

成功后,终端会显示部署版本和类似下面的地址:

https://ido-content-portal.<你的-workers-subdomain>.workers.dev

如果账号中已经存在 ido-content-portal,这条命令可能更新同名 Worker。不能确认它属于当前站点时,应先到 Workers & Pages 控制台核对,或修改 wrangler.jsonc 中的 name

把实际域名替换到下面的命令中:

curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/
curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/english/
curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/blog/
curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/blog/posts/deploy-site-to-cloudflare/
curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/blog/rss.xml
curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/blog/sitemap-index.xml

有效地址应返回 200,或为了规范末尾斜杠先返回一次 301308,随后到达 200。再检查错误地址:

curl -I https://ido-content-portal.<你的-workers-subdomain>.workers.dev/blog/not-exists/

它应返回 404,不能返回门户首页和 200。最后还要用真实浏览器逐页查看,因为 curl -I 不能证明样式和交互正常。

八、接入正式域名

当前上传的是完整门户,/blog/ 已经真实存在于门户 dist/ 中。因此只需要把根域名绑定到整个 Worker,不需要为博客单独准备源站。

1. 确认域名已经接入 Cloudflare

如果 idozhuoyong.com 已经在当前账号中显示为 Active,直接进入下一步。否则:

  1. 进入 Cloudflare 的 Domains,选择 Onboard a domain
  2. 输入 idozhuoyong.com 并选择计划。
  3. 核对扫描出的 DNS 记录,尤其是 MX、TXT、DKIM 和 SPF 等邮箱记录。
  4. 如果注册商启用了 DNSSEC,先关闭旧 DNSSEC。
  5. 在域名注册商后台,将权威 Nameserver 替换成 Cloudflare 提供的两个地址。
  6. 等待域名状态变为 Active,之后再按 Cloudflare 提示重新启用 DNSSEC。

Nameserver 更新可能需要一段时间。不要删除与网站无关的邮箱、验证或其他业务记录。Cloudflare 完整 DNS 接入流程

2. 绑定根域名

只有 workers.dev 验证通过后才执行:

  1. 打开 Workers & Pages
  2. 选择 ido-content-portal
  3. 进入 Settings → Domains & Routes
  4. 选择 Add → Custom Domain
  5. 输入 idozhuoyong.com
  6. 核对目标 Worker 后确认。
  7. 等待证书和域名状态正常。

Custom Domain 会让该 Worker 成为整个主机名的源站,Cloudflare 会创建需要的 DNS 记录并签发证书。Workers Custom Domains

3. 先处理可能的冲突

如果 idozhuoyong.com 已经有 A、AAAA、CNAME、Worker Route 或其他生产站点,先记录原配置、当前用途和恢复方式。Cloudflare 不允许在已有冲突 CNAME 的主机名上直接创建 Custom Domain。

不要在不清楚用途时删除 DNS 记录,也不要把 MX、TXT 等记录当作网站冲突项。若当前域名承载着其他生产网站,应先停止切换并明确迁移方案。

4. 不要增加博客转发规则

绑定根域名后,//english//blog/ 会一起生效。不要再添加把 /blog/* 指向其他 Pages 项目的 Origin Rule、URL Rewrite 或反向代理,否则会绕过门户聚合结果并增加路径与缓存故障。

5. 验证正式域名

依次打开:

https://idozhuoyong.com/
https://idozhuoyong.com/english/
https://idozhuoyong.com/blog/
https://idozhuoyong.com/blog/posts/deploy-site-to-cloudflare/
https://idozhuoyong.com/blog/archives/
https://idozhuoyong.com/blog/tags/
https://idozhuoyong.com/blog/about/
https://idozhuoyong.com/blog/rss.xml
https://idozhuoyong.com/blog/sitemap-index.xml

检查 HTTPS 证书、文章直达和刷新、静态资源、Canonical、RSS、站点地图及手机端布局。/blog/not-exists/ 必须返回 404。

九、发布后的完整检查

按下面的顺序检查,出现问题时更容易定位:

  1. workers.dev 上的门户、英语课程和博客能否打开。
  2. idozhuoyong.com 是否使用有效 HTTPS 证书。
  3. 门户卡片能否进入两个已发布子站。
  4. 随机选择一篇文章,直接输入完整 URL 并刷新。
  5. 开发者工具中是否存在资源 404、重定向循环或 Mixed Content。
  6. RSS 和站点地图是否返回 XML,且内部 URL 使用正式域名。
  7. 页面 Canonical 是否指向 https://idozhuoyong.com/blog/...
  8. 不存在的博客地址是否返回 404。
  9. 桌面端和手机端是否各完成一次真实浏览。

如果 workers.dev 正常而正式域名异常,优先检查域名是否 Active、Custom Domain 是否绑定到正确 Worker,以及是否存在 DNS 或 Worker Route 冲突。如果 workers.dev 也异常,先检查门户 dist/ 和 Wrangler 上传结果。

十、常见问题

页面能打开,但样式全丢了

检查浏览器是否请求 /blog/_astro/...。如果变成 /_astro/...,说明博客构建时丢失了 base: '/blog' 配置。当前 astro.config.mjs 已正确配置,不要删除。

首页正常,文章刷新后 404

先检查 ${PROJECTS_DIR}/ido-content-portal/dist/blog/posts/<slug>/index.html 是否存在,再确认 Wrangler 上传的是门户 dist/,并且没有错误的 /blog/* 转发规则。

门户能打开,但 /blog/ 是 404

通常是构建顺序错误。先执行博客 npm run build,再执行门户 npm run buildnpm run check;确认日志出现“已接入 /blog/”后重新部署。

博客显示的是旧文章

门户复制的是博客上一次生成的 dist/。修改 Markdown 后必须先重建博客,再重建并部署门户。只执行 wrangler deploy 不会自动运行这两个构建步骤。

需要手动回滚

在 Worker 的 Deployments 中找到上一个正常版本,打开菜单并选择 Rollback;也可以执行 npx wrangler@latest rollback。回滚只改变 Cloudflare 上的版本,不会修改本地源码或 Git。Workers 版本回滚

十一、推荐的发布流程

如果只修改博客,按这个顺序执行:

cd "$PROJECTS_DIR/ido_blog"
npm run build

cd "$PROJECTS_DIR/ido-content-portal"
npm run build
npm run check
npx wrangler@latest deploy

完整流程是:

写 Markdown
  → 构建博客
  → 构建并检查门户
  → 检查 Git 状态与最终 dist
  → Wrangler 上传
  → 检查正式 URL

部署不会自动执行 Git 提交,也不要把“部署成功”当成“代码已经推送”。上传前运行 git status,避免把尚未确认的本地内容发布。

首次上线先保持 Workers Static Assets 默认缓存。博客的 Astro CSS 带内容哈希,但英语课程的 app.jscontent.jsstyles.css 没有内容哈希,不适合全站使用长期 immutable 缓存。等资源版本策略稳定后,再通过 _headers 精确设置。Workers Static Assets 响应头与缓存

当前三个项目相互独立,普通 Git 构建无法读取仓库外的相邻目录。后续建立 CI 时,可以让流水线同时检出三个仓库,或者让子项目发布带版本的静态产物,再由门户下载并聚合。首次上线应先跑通手动构建、部署、验证和回滚。

十二、最终验收清单

  • 博客 npm run build 通过。
  • 门户 npm run buildnpm run check 通过。
  • 门户日志显示 /english//blog/ 已接入。
  • wrangler deploy --dry-run 通过。
  • workers.dev 上的门户、英语课程、博客、文章、RSS 和站点地图正常。
  • idozhuoyong.com 在 Cloudflare 中处于 Active。
  • Custom Domain 绑定到正确 Worker。
  • 正式域名的主要页面和静态资源正常。
  • 不存在的博客地址返回 404。
  • 桌面端与手机端均已人工检查。
  • 已确认从 Deployments 回滚到上一版本的入口。

完成这份清单后,idozhuoyong.com 才算具备可重复、可验证和可恢复的发布流程。

参考资料