文章

用 Cloudflare Workers 搭建个人站点

为什么不选 Pages,/zh/ 下为什么不能出现英文,以及两次看起来像成功的部署失误。

发布于

  • #cloudflare
  • #astro

这不是一篇从零教你点菜单的 Astro 教程。站已经在了。我想留下来的是理由:文件为什么放在 Workers 上,有哪条语言规则我不肯破,以及两次看起来像部署成功的失误。

想抄接线,从仓库开始:tyler-y-liu/personal-site

英文首页:站名、一句话介绍,以及 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 角标。
我故意把一篇只有英文的文章留在中文列表上,好拍下这张图。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,除非你把真实地址写进两处:

  1. astro.config.mjssite
  2. public/robots.txt 里的 Sitemap: 一行

然后再部署一次。我用 curl/,期望 200;再查一条不存在的路径,期望 404,响应体是我的 404 页。

不要抄 Worker 的 main

网上大多数 Wrangler 片段都假设你有一段脚本。这个项目没有。加上 main,等于告诉 Cloudflare 去跑一份你没有的代码。

上面那份配置就是全部:一个目录,加上 404 策略。

然后再做 push 即发布

第一次部署我故意用手做。出了问题,我希望分得清是构建坏了,还是自动化坏了。

从 Markdown 经 git push、GitHub CI、Workers Builds,到线上 workers.dev 的流程。
手工部署通了之后,push 就够了。

GitHub 上的 CI 是三条命令:pnpm vitest runpnpm astro checkpnpm build。Node 版本读 .nvmrc,本地和 CI 对齐。

然后到 Cloudflare 控制台:

  1. 打开 personal-site 这个 Worker
  2. Settings → Build → Connect to Git,选这个仓库
  3. 构建命令:pnpm build
  4. 部署命令:pnpm wrangler deploy

那一页我没有截图。要填的就是这四项。存好之后,push 到 main 就是发布。

现在怎么写文章

  1. 新建 src/content/blog/en/<slug>.md
  2. 同一天要中文,就在 zh/ 下建同名文件,并把 sourceUpdated 填成英文版的 updatedDatepubDate
  3. git push

draft: true 不会进生产构建。把草稿留在仓库里,不需要 CMS。

这就是我想要的链路:一个 Markdown 文件,一次静态构建,一个只负责吐文件的 Worker。

返回博客