文章
用 Cloudflare Workers 搭建个人站点
为什么不选 Pages,/zh/ 下为什么不能出现英文,以及两次看起来像成功的部署失误。
发布于
- #cloudflare
- #astro
这不是一篇从零教你点菜单的 Astro 教程。站已经在了。我想留下来的是理由:文件为什么放在 Workers 上,有哪条语言规则我不肯破,以及两次看起来像部署成功的失误。
想抄接线,从仓库开始:tyler-y-liu/personal-site。
我想要主页和博客共用一个域名。英文是原文,中文是译文。文章写在 git 里的 Markdown 里,发布就是 push。托管得是一个一年后还不用搬家的地方。
为什么是 Workers,不是 Pages
Pages 还在。但 Cloudflare 对新项目指的是 Workers + Static Assets。访客照样拿到 HTML 和 CSS,挂在 *.workers.dev 上,请求也不计费。
差别在平台剩下的那部分。配置写在仓库里的 wrangler.jsonc。以后要加 Cron、KV、R2,或真的写一段 Worker 代码,都加在这个项目里,不用换主机。
自定义域名可以后绑。到时候不改站点代码。
那一条语言规则
英文是唯一原文。先改那份文件。中文是它的译文,不是第二份原文。同名即配对:
src/content/blog/
en/this-post.md ← 真相来源
zh/this-post.md ← 同名,或者根本不存在
/zh/下的 URL,绝不出现英文正文。
一篇文章还没有译文时,中文列表仍然显示它。卡片留着英文标题,标上 EN,链接离开 /zh/。我不会给一篇英文正文生成中文详情路由。
EN 角标才是重点。点进去,你已经在 /blog/... 上了。语言切换也按这个走。对侧有这篇文章,就跳过去;没有,就跳到对侧的博客列表。缺译不是 404。
译文会落后。这是正常的。每篇中文可以声明 sourceUpdated:我翻译那天英文版的日期。星期二改了英文、忘了中文,星期五的构建照样成功。它会打印一行警告,说译文可能过期了。翻译落后,不该挡住发布。
没有 Worker 脚本
wrangler.jsonc 指向 Astro 的输出目录。没有 main,没有脚本,就是文件:
{
"name": "personal-site",
"compatibility_date": "2026-08-11",
"assets": {
"directory": "./dist",
"not_found_handling": "404-page"
}
}
not_found_handling: "404-page" 让未知路径返回自定义 404 页,而且状态码是真正的 404,不是空响应。那一页把中英文案并排放着。路径都不存在了,没办法可靠地知道访客想看哪种语言。
Astro 7 要 Node 22.12 或更高,奇数主版本(比如 23)不受支持。我当时是 22.9。先升级,再写主页。
然后第一次部署就是四条命令:
pnpm add -D wrangler
pnpm exec wrangler login
pnpm build
pnpm exec wrangler deploy
我把后两步收成了 pnpm deploy。Wrangler 打出一个 *.workers.dev 地址。站能打开。失误从这里开始。
两次看起来像成功的坑
第一次部署会骗你
站已经能打开了。canonical、RSS、sitemap 里却还是 https://example.com,除非你把真实地址写进两处:
astro.config.mjs的sitepublic/robots.txt里的Sitemap:一行
然后再部署一次。我用 curl 查 /,期望 200;再查一条不存在的路径,期望 404,响应体是我的 404 页。
不要抄 Worker 的 main
网上大多数 Wrangler 片段都假设你有一段脚本。这个项目没有。加上 main,等于告诉 Cloudflare 去跑一份你没有的代码。
上面那份配置就是全部:一个目录,加上 404 策略。
然后再做 push 即发布
第一次部署我故意用手做。出了问题,我希望分得清是构建坏了,还是自动化坏了。
GitHub 上的 CI 是三条命令:pnpm vitest run、pnpm astro check、pnpm build。Node 版本读 .nvmrc,本地和 CI 对齐。
然后到 Cloudflare 控制台:
- 打开
personal-site这个 Worker - Settings → Build → Connect to Git,选这个仓库
- 构建命令:
pnpm build - 部署命令:
pnpm wrangler deploy
那一页我没有截图。要填的就是这四项。存好之后,push 到 main 就是发布。
现在怎么写文章
- 新建
src/content/blog/en/<slug>.md - 同一天要中文,就在
zh/下建同名文件,并把sourceUpdated填成英文版的updatedDate或pubDate git push
draft: true 不会进生产构建。把草稿留在仓库里,不需要 CMS。
这就是我想要的链路:一个 Markdown 文件,一次静态构建,一个只负责吐文件的 Worker。