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 上,并绑定到自己的域名。
最终结果是:
- 前台:https://blog.oknm.de
- 后台:https://blog.oknm.de/admin
- 前端:Cloudflare Pages
- 后端:Cloudflare Workers
- 数据库:Cloudflare D1
- 对象存储:Cloudflare R2
- 增强统计:Workers 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 200https://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。整体维护成本低,扩展也清晰。对于个人博客来说,这个架构已经足够干净。