Monolith Blog 部署到 Cloudflare 的完整记录

记录一次从 Mac mini 部署 Monolith 到 Cloudflare Pages、Workers、D1、R2 和 Analytics Engine 的完整过程,包括域名、后台、统计、封面图和延迟观察。

工程笔记 · 2026-05-25 · 约 8 分钟阅读 · 标签:Cloudflare、Monolith、部署记录

这篇文章记录一次从零部署 Monolith 的过程。目标很明确:用 Mac mini 作为部署控制机,把博客真正跑在 Cloudflare Pages、Workers、D1、R2 和 Analytics Engine 上,并绑定到自己的域名。

最终结果是:

为什么用 Mac mini 部署

一开始有两个选择:Mac mini 和甲骨文服务器。

Monolith 本身更适合 Cloudflare 边缘部署,而不是传统 VPS 部署。它的前端、后端、数据库和对象存储都能直接落到 Cloudflare 上。Mac mini 只负责本地构建、登录 Cloudflare、执行 Wrangler 部署命令,不承担线上流量。

这样做的好处是:

  • 不占用 VPS 资源
  • 不需要维护 Node 常驻服务
  • 不需要自己处理 HTTPS 和反向代理
  • Pages 和 Workers 自动跑在 Cloudflare 边缘网络
  • D1、R2、Analytics Engine 都在同一个平台内闭环

所以最后的策略是:Mac mini 负责部署,Cloudflare 负责运行。

部署资源

这次创建和使用的 Cloudflare 资源包括:

  • Pages 项目:monolith-client
  • Worker:monolith-server
  • D1 数据库:monolith-db
  • R2 Bucket:monolith-assets
  • Analytics Engine Dataset:monolith_analytics
  • 自定义域名:blog.oknm.de

Wrangler 登录后,先创建 D1 和 R2,然后把 server/wrangler.toml 里的数据库 ID 改成当前账号真实的 D1 ID。这里要特别注意:开源仓库里的示例 D1 ID 不能直接拿来用。

D1 和 R2

D1 创建完成后,部署脚本会执行远程迁移:

npm run deploy:cloudflare

这一步会把文章表、标签表、评论表、设置表、统计表等 schema 迁移到 D1。迁移完成后,又执行了一次 schema reconcile,补齐运行时需要的兼容列。

R2 用作媒体资源、备份文件和上传图片存储。部署完成后,我测试过上传接口,确认 R2 写入和删除都正常。

后台密码和 JWT Secret

后台密码和 JWT Secret 没有写进仓库,而是通过 Wrangler Secrets 注入 Worker:

npx wrangler secret put ADMIN_PASSWORD --name monolith-server
npx wrangler secret put JWT_SECRET --name monolith-server

后面后台密码又更新了一次,同样是通过 secret 更新完成。这个方式比把密码写进配置文件安全很多。

自定义域名 blog.oknm.de

Pages 默认域名是 monolith-client-exu.pages.dev。后来把 blog.oknm.de 加到了 Pages 自定义域名里。

这里踩了一个小坑:Cloudflare Pages 已经添加了自定义域名,但 DNS 还指向旧记录,导致状态一直停在:

CNAME record not set

最后把 DNS 改成:

Type: CNAME
Name: blog
Target: monolith-client-exu.pages.dev
Proxy: Proxied

等 Cloudflare 验证完成后,Pages 自定义域名状态变为 active,访问 https://blog.oknm.de 返回 HTTP/2 200

Analytics Engine

Monolith 支持 Cloudflare Workers Analytics Engine。它分两部分:

  • 写入:Worker 通过 Analytics Engine binding 写入访问数据
  • 读取:后台通过 Cloudflare SQL API 查询数据

一开始部署 Worker 时遇到错误:

You need to enable Analytics Engine

启用 Dashboard 里的 Analytics Engine 后,再用新版 Wrangler 发布,AE binding 才部署成功。

之后又创建了一个只读 API Token,权限包含 Account Analytics Read,再把下面两个 secret 写进 Worker:

npx wrangler secret put CLOUDFLARE_ACCOUNT_ID --name monolith-server
npx wrangler secret put CLOUDFLARE_API_TOKEN --name monolith-server

完成后,后台 AE 增强分析接口可以返回真实统计数据,包括访问量、地区、设备、浏览器、停留时间和运营建议。

品牌和站点配置

部署完成后,把默认的 Monolith 品牌改成了自己的站点名:

__22号仔Stringer🫧 Blog

修改范围包括:

  • 顶部导航品牌名
  • 首页站点标题
  • 后台侧栏标题
  • 登录页标题
  • PWA manifest
  • HTML meta / Open Graph / Twitter Card
  • Worker 环境变量 BLOG_NAME
  • Worker 环境变量 SITE_ORIGIN

SITE_ORIGIN 最终设置为:

https://blog.oknm.de

这样 sitemap、robots、RSS 和 SEO 相关的绝对 URL 都会指向正式域名。

默认封面图

初始文章没有封面图,文章列表会显示首字占位。后来接入了一个随机图接口:

https://www.dmoe.cc/random.php

现在逻辑是:

  • 文章有自己的 coverImage,优先用文章封面
  • 文章没有封面,自动调用随机图
  • 每次页面加载生成新的随机参数,刷新页面会换图
  • 如果随机图加载失败,回退到原来的文字占位

这不是把图片保存到文章里,而是无封面时的动态展示兜底。以后如果想让每篇文章封面固定,可以再批量拉取图片、上传到 R2,并写入每篇文章的 cover_image 字段。

验收结果

最后做了这些验证:

  • https://blog.oknm.de 返回 HTTP/2 200
  • https://blog.oknm.de/admin 返回 HTTP/2 200
  • /api/health 正常
  • 后台登录成功
  • D1 迁移完成
  • R2 上传和删除正常
  • Analytics Engine 写入接口返回 204
  • 后台 AE 查询接口返回 HTTP/2 200
  • Pages 自定义域名状态为 active

关于国内延迟

用 ITDOG 测试后,中国大陆访问平均大约在 180ms 到 220ms,港澳台明显更低。

这个结果基本符合预期。因为当前架构是 Cloudflare Pages + Workers,没有接入国内 CDN,也没有备案线路优化。Cloudflare 对港澳台和海外访问体验很好,但大陆跨境访问延迟偏高是常见情况。

短期可以接受。真正要优化大陆访问,需要备案和国内 CDN,或者使用 Cloudflare China Network 这类企业方案。

小结

这次部署的最终形态是一个比较完整的 Cloudflare 原生博客系统:

  • Pages 托管前端
  • Workers 提供 API
  • D1 保存文章和配置
  • R2 保存媒体和备份
  • Analytics Engine 做访问分析
  • 自定义域名走 Cloudflare DNS

Mac mini 只是部署控制机,线上运行完全交给 Cloudflare。整体维护成本低,扩展也清晰。对于个人博客来说,这个架构已经足够干净。

全部文章 · 返回 OneMJJ 首页

OneMJJ · 少踩坑,多留传家宝 · Public tools first.