一个为写作而生的 Cloudflare 原生个人博客。公开站点、写作后台与内容存储彼此分离;博客通过 Service Binding 读取内容,不向公开前台暴露管理 API。
项目处于首个可用版本,适合个人部署和二次开发。正式使用前请完成 Cloudflare Access 配置,并自行评估数据备份与升级策略。
| 博客首页 | 文章详情 |
|---|---|
![]() |
![]() |
| 后台概览 | 文章编辑器 |
|---|---|
![]() |
![]() |
- Astro SSR,响应式纸张风格界面,支持浅色、深色与跟随系统主题
- 首页、文章详情、独立关于页、可选短文时间轴、归档、标签、系列与上一篇/下一篇导航
- 客户端搜索索引、RSS、Sitemap、Canonical URL 与基础 SEO 元数据
- 阅读时长、目录、封面、站点图标、限时草稿预览
- Markdown 内容经过服务端清理,原始 HTML 和任意 iframe 不会直接透传
- React + Hono 管理后台,支持草稿、发布与归档状态
- 可选的独立短文管理页,支持纯文本、正文
#标签、图片、视频预览、草稿/发布、置顶、编辑与即时删除 - 草稿自动保存;已发布文章修改后需显式点击“更新”才会公开
- 专注写作、实时预览、版本快照、恢复历史与并发版本冲突提示
- 标签、系列分组与排序、站点导航、社交链接、主题色、短文介绍和 SEO 设置
- 批量发布、转为草稿、归档与删除;破坏性操作带确认或版本校验
- 图片上传至 R2,元数据保存在 D1,可设置替代文本,并用于文章正文或短文附件
- 在线视频只保存标题与规范化外链,不下载、不上传到 R2
- 支持 YouTube、Bilibili、Vimeo,以及 HTTPS
.mp4/.webm直链 - 媒体库支持图片/视频筛选、搜索与预览;编辑器提供桌面侧栏和移动端抽屉
- 视频链接由服务端白名单解析并重建播放器地址,无法识别的地址安全降级
- Cloudflare Access 保护后台;Worker 再次校验 Access JWT 的签名、issuer 与 AUD
- 浏览器写操作额外校验 Same-Origin
- Blog Worker 通过 RPC Service Binding 调用 CMS 内容服务
- 内置无状态 Streamable HTTP MCP,可供 Codex 等客户端搜索、读取和管理文章
- D1 保存文章、版本与短文,R2 只保存图片,媒体通过公开 Blog Worker 输出
flowchart LR
Reader["读者浏览器"] --> Blog["Blog Worker<br/>Astro SSR"]
Author["作者浏览器"] --> Access["Cloudflare Access"] --> CMS["CMS Worker<br/>React + Hono"]
MCP["MCP 客户端"] --> Access
Blog -->|Service Binding RPC| CMS
CMS --> D1[(D1)]
CMS --> R2[(R2 图片)]
Blog -->|公开媒体代理| R2
| 部分 | 技术 |
|---|---|
| 公开站点 | Astro、Cloudflare Workers |
| 管理后台 | React、React Router、Vite、Hono |
| 数据与媒体 | Cloudflare D1、R2 |
| 内容处理 | TypeScript、Zod、Unified / Remark / Rehype |
| 身份验证 | Cloudflare Access、JWT |
| 自动化接口 | MCP SDK、Cloudflare Agents |
| 工程化 | pnpm workspace、Vitest、Wrangler |
.
├── apps/
│ ├── blog/ # Astro SSR 公开站点
│ └── cms/ # React 管理界面与 Hono Worker
├── packages/
│ ├── contracts/ # 共享类型、Zod 契约、媒体 URL 规范化
│ └── markdown/ # Markdown 渲染、清理、摘要与阅读时长
├── migrations/ # D1 增量迁移
├── scripts/ # 本地/远程演示数据脚本
└── docs/ # Access 与 MCP 的专项配置文档
- Node.js
^20.19.0或>=22.12.0 - pnpm
11.15.1(仓库已通过packageManager固定) - 本地开发不要求真实 Cloudflare 账号
git clone <your-repository-url>
cd cf-blog
corepack enable
pnpm install
pnpm types
pnpm db:migrate:local
pnpm db:seed:demo:local # 可选,写入演示文章
pnpm dev本地服务地址:
- 管理后台:http://localhost:5173
- CMS Worker:http://localhost:8787
- Blog:http://localhost:4321
Wrangler 会把本地 D1 和 R2 数据保存在 apps/cms/.wrangler/state,该目录不会提交到 Git。开发脚本只在 ENVIRONMENT=development 且请求来自 localhost 时启用本地身份;远程环境不会绕过 Access。
三个服务会由根目录的 pnpm dev 并行启动。也可以分别运行:
pnpm dev:cms
pnpm dev:admin
pnpm dev:blogpnpm typecheck # TypeScript 与 Astro 检查
pnpm test # 单元与回归测试
pnpm build # CMS 与 Blog 生产构建
pnpm check # 依次执行以上全部检查测试覆盖共享契约、文章版本与状态变更、短文输入/附件/删除、MCP 工具、媒体操作、视频 URL 规范化、安全 Markdown 渲染和光标插入逻辑。
登录 Cloudflare:
pnpm exec wrangler login在部署前检查并按需修改:
apps/cms/wrangler.jsonc中的 Worker、D1、R2 名称和环境变量apps/blog/wrangler.jsonc中的 Worker 名称及指向 CMS 的 Service Binding- 两个配置中的 Service Binding 服务名必须一致
CMS 环境变量:
| 变量 | 用途 | 示例 |
|---|---|---|
ENVIRONMENT |
运行环境;线上保持 production |
production |
ACCESS_TEAM_DOMAIN |
Zero Trust team domain,含 https:// |
https://team.cloudflareaccess.com |
ACCESS_AUD |
CMS Access Application 的 Audience Tag | your-audience-tag |
BLOG_URL |
公开博客根地址,用于生成预览链接 | https://blog.example.com |
MEDIA_BASE_URL |
公开图片地址前缀 | https://blog.example.com/media |
这些配置值本身不是密码。Access Service Token 等敏感值不要写入 wrangler.jsonc、.dev.vars 示例、提交记录或日志;需要 Worker secret 时使用 wrangler secret put。
默认配置使用名为 cf-blog-media 的 R2 bucket。首次部署前创建它;如果修改了 bucket_name,命令也要使用相同名称:
pnpm exec wrangler r2 bucket create cf-blog-mediaD1 binding 未保存账号专属 ID。当前 Wrangler 会在执行远程迁移时自动配置缺失的 D1 资源,然后按顺序应用 migrations/:
pnpm db:migrate:remote如果团队不使用自动配置,也可以先手动创建 D1,再把 database_id 写入 CMS 的 Wrangler 配置。
pnpm check
pnpm db:migrate:remote
pnpm --filter @cf-blog/cms deploy
pnpm --filter @cf-blog/blog deploy顺序很重要:先检查,再迁移数据库,再发布 CMS,最后发布依赖 CMS Service Binding 的 Blog。配置完成后可直接使用同等顺序的快捷命令:
pnpm deploy升级已有站点时同样必须先执行远程迁移。本版本的短文表、附件关系、功能开关和公开页介绍分别由 0005 至 0008 migration 增量创建;迁移不会因关闭短文功能而删除已有内容。
首次发布后:
- 为 CMS 的
workers.dev或自定义管理域名创建 Cloudflare Access Application。 - 复制 team domain 与 AUD,回填 CMS 配置。
- 将
BLOG_URL和MEDIA_BASE_URL改为真实公开地址。 - 运行
pnpm types,再次执行pnpm deploy。 - 验证无痕窗口先进入 Access 登录,而公开博客、RSS 和
/media/*不会跳转到登录页。
完整步骤见 Cloudflare Access 配置。Cloudflare 的 Wrangler 配置文档 与 D1 migration 文档 可用于确认资源和迁移行为。
建议使用两个域名:
blog.example.com→ Blog Workeradmin.example.com→ CMS Worker,并由 Access 保护
正式域名验证完成后,可将两个 wrangler.jsonc 的 workers_dev 与 preview_urls 改为 false,避免继续暴露临时地址。修改绑定、变量或兼容性日期后运行 pnpm types,让生成的 Worker 类型与配置保持一致。
CMS Worker 在 /mcp 提供文章管理工具,并复用同一套 Access 鉴权、D1 服务和版本冲突控制。建议为自动化客户端创建独立的 Cloudflare Access Service Token;不要复用浏览器身份或将 Token 提交到仓库。
配置示例、工具边界与凭证轮换见 Codex MCP 接入与运维。
日常写作、媒体管理、分组、站点设置与本地调试流程见 后端(CMS)功能使用指南。
| 命令 | 作用 |
|---|---|
pnpm dev |
并行启动 CMS Worker、管理界面和 Blog |
pnpm types |
根据 Wrangler 配置生成 Worker 类型 |
pnpm db:migrate:local |
应用本地 D1 migration |
pnpm db:migrate:remote |
应用远程 D1 migration |
pnpm db:seed:demo:local |
幂等写入本地演示文章 |
pnpm db:seed:demo |
幂等写入远程演示文章 |
pnpm check |
类型检查、测试与生产构建 |
pnpm deploy |
检查、迁移、部署 CMS、部署 Blog |
欢迎提交问题和改进。开始前请阅读 CONTRIBUTING.md;安全问题请按 SECURITY.md 私下报告。



