无需服务器！零成本搭建一个带后台的个人博客，薅秃Cloudflare所有免费功能

前言新人写博客第一个门槛就是挑选一个博客系统，比如我现在用WordPress功能强大但需要部署到服务器上，静态博客系统如Hexo可以把前端发布到GitHub pages，但后端装在本地不方便随时修改。这个项目是基于Cloudflare生态的全栈现代化博客CMS，比较有意思的是作者几乎用到了Cloudflare的所有免费服务，功能也很强大。 作者的部署教程写的非常详细，我就直接照搬了，项目更新很频繁，有任何问题都可以在电报群直接询问作者。 项目地址：https://github.com/du2333/flare-stack-blog 项目说明默认界面作者用的fuwari主题核心功能 Cloudflare 生态核心配置预览 在开始之前，先看看这两种方式的差异：两种的额度都挺慷慨的，根本用不完，其中GitHub Actions对于公开仓库是免费用，2000分钟是对于私有仓库的限制。第一阶段：前置准备（通用）无论选择哪种部署方式，你都需要先准备好这些「基础设施」。 Fork 本仓库 (必备) 这是所有部署的第一步。点击仓库右上角的 Fork 按钮，将项目源码克隆到你自己的 GitHub 账号下。只有 Fork 到自己的账号，你才有权配置密钥和触发自动部署。注册与启用服务 Cloudflare 账号：注意需绑定付款方式以启用免费额度充足的 R2 和 Workers AI 服务（个人博客通常不会产生费用）。域名托管：将你的域名 DNS 托管到 Cloudflare，这是使用免费 CDN 和自动化部署的前提。创建 Cloudflare 资源 在 Cloudflare Dashboard 中创建以下资源并记录其名称/ID： R2 存储桶：用于存储图片和静态资源（记录存储桶名称）。 D1 数据库：用于存储文章和配置（记录 Database ID）。 KV 命名空间：用于缓存（记录 Namespace ID）。 Queues 消息队列：用于处理异步任务（队列名称为 blog-queue）。获取核心凭证 (IDs) 你需要以下两个 ID 贯穿整个部署过程： Account ID：域名的概览页右侧查看。 Zone ID：域名的概览页右侧查看。 Account Home -> 你的域名创建 API 令牌 (Token) 我们需要赋予部署脚本操作你账户的权限。点击右上角 头像 -> 我的个人资料 -> API 令牌 -> 创建令牌。 A. CDN 刷新令牌 (必填) 模板：使用「编辑区域 DNS」模板。权限：区域 -> 清除缓存 -> 清除。资源：包括 -> 所有区域（或指定域名）。用途：应用部署后自动强制更新 CDN 缓存。 B. 部署令牌 (仅方案一需要) 模板：使用「编辑 Cloudflare Workers」模板。权限：添加更多 -> D1 -> 编辑。资源：包括 -> 所有区域（或指定域名）用途：允许 GitHub Actions 远程部署代码和执行数据库迁移。创建 GitHub OAuth App 为了实现 GitHub 登录功能：前往 GitHub Settings -> Developer Settings -> OAuth Apps -> New OAuth App。 Homepage URL: https://<你的域名> Authorization callback URL: https://<你的域名>/api/auth/callback/github 创建后记录 Client ID，并生成一个新的 Client Secret。第二阶段：选择部署方案方案一：GitHub Actions 自动部署通过 GitHub 的服务器进行构建和分发。启用Actions 默认情况下，GitHub 为了安全考虑，不会在 Fork 的仓库中自动启用 Actions。需要在仓库设置里启用配置仓库变量 在 GitHub 仓库中，进入 Settings -> Secrets and variables -> Actions，点击 New repository secret 添加以下变量： A. 必填部署变量配置（Secrets - CI/CD） CLOUDFLARE_API_TOKEN：步骤 5中 的部署令牌 CLOUDFLARE_ACCOUNT_ID：你的 Account ID D1_DATABASE_ID：D1 数据库 ID KV_NAMESPACE_ID：KV 命名空间 ID BUCKET_NAME：R2 桶名称 B. 必填运行时配置（Secrets - 运行时） BETTER_AUTH_SECRET：终端运行 openssl rand -hex 32 生成 BETTER_AUTH_URL：应用 URL（如 https://blog.example.com） ADMIN_EMAIL：管理员邮箱 GH_CLIENT_ID：GitHub OAuth Client ID GH_CLIENT_SECRET：GitHub OAuth Client Secret CLOUDFLARE_ZONE_ID：你的 Zone ID CLOUDFLARE_PURGE_API_TOKEN：步骤 5 中的刷新令牌 DOMAIN：博客域名（如 blog.example.com） C. 选填运行时配置 PAGEVIEW_SALT：浏览量统计的访客匿名化 salt，用于增强访客匿名化，终端运行 openssl rand -hex 16 生成，或者任意16位左右的字符。 GH_TOKEN：用于检查版本更新，由于多个Workers共享一个IP，很大概率导致GitHub限流，配置此token就可以避免限流，前往New Fine-grained Personal Access Token设置，默认权限即可，过期时间自定义：https://github.com/settings/personal-access-tokens/new UMAMI_SRC：Umami 客户端埋点代理 URL（如 https://cloud.umami.is） VITE_UMAMI_WEBSITE_ID：Umami Website ID（客户端埋点），这个既是运行时变量，也是构建时变量，不过要填Variables不是Secrets，见下触发部署 进入 GitHub 仓库的 Actions 标签页，启用并手动运行 Deploy 工作流。后续你每次推送代码到仓库，系统都会自动更新博客。方案二：Cloudflare Dashboard 直接部署直接在 Cloudflare Workers上连接仓库。修改配置文件 在本地或 GitHub 网页端将 wrangler.example.jsonc 复制并重命名为 wrangler.jsonc，替换其中的占位符，不要自行删减 binding，除非你知道在改什么 // 这里只展示一部分 { "keep_vars": true, // 每次构建不清楚运行时变量 "routes": [{ "pattern": "blog.example.com", "custom_domain": true }], "d1_databases": [{ "binding": "DB", "database_id": "你的-D1-ID", ... }], "r2_buckets": [{ "binding": "R2", "bucket_name": "你的-R2-名称", ... }], "kv_namespaces": [{ "binding": "KV", "id": "你的-KV-ID", ... }] } 创建并连接工程在 Cloudflare Dashboard 进入 Workers 和 Pages -> 创建 -> 连接到 Git。选择你的仓库，并配置构建设置： Framework preset: None Build command: bun run build Deploy command: bun run deploy 添加环境变量：在构建配置中添加 BUN_VERSION: 1.3.5。添加所有以 VITE_ 开头的前端变量。配置运行时变量 部署完成后，进入该 Worker 的 设置 -> 变量 -> 机密，点击 添加机密，填入 BETTER_AUTH_SECRET、GITHUB_CLIENT_ID、ADMIN_EMAIL 等敏感配置，具体变量详见方案一的运行时变量表格。 注意变量名：在 Cloudflare Dashboard 中，Github的变量名必须使用全称： GH_CLIENT_ID → GITHUB_CLIENT_ID GH_CLIENT_SECRET → GITHUB_CLIENT_SECRET GH_TOKEN → GITHUB_TOKEN **CDN 缓存**：方案二由于不经过 GitHub Actions，不会自动清除缓存。每次部署后，请在博客后台「设置」页面手动点击「清除 CDN 缓存」，如果还没注册管理员账号，出现网页样式丢失无法导航，前往cloudflare面板里清除缓存第三阶段：可选进阶配置图片优化 (Cloudflare Images) 在管理页为你的域名开启 图片转换。每月 5000 次免费转换额度，能极大提升博客图片的加载速度。邮件系统 支持SMTP邮件，以Resend为例 注册 Resend 并绑定域名，推荐绑定子域名。https://resend.com/ 获取 API Key 后，填入博客后台的「设置」页面。 host: smtp.resend.com port: 465 user: resend password: 你的api key 开启后，你的博客将支持：密码登录、验证码安全校验、评论回复邮件通知。人机验证 (Cloudflare Turnstile) 前往Cloudflare Turnstile页面创建一个Widget，记录site key和secret key 填写 VITE_TURNSTILE_SITE_KEY 构建时变量，仓库变量 TURNSTILE_SECRET_KEY 运行时变量，仓库机密 填入重新部署生效个性化配置目前除了主题需要配置环境变量，其他的站点信息都可以在后台个性化配置板块自行配置 Github Actions部署的用户，需要设置新的THEME变量（非机密） Workers Build部署的用户，需要在构建时变量里设置（非运行时变量）第四阶段：后续维护与更新同步上游更新当管理后台提示有新版本时（或定期检查 GitHub 仓库更新），你只需：进入你 Fork 的仓库主页。点击 Sync fork -> Update branch。自动部署：方案一：GitHub Actions 会感应到代码更新并自动触发部署。方案二：Cloudflare 会自动检测到 GitHub 的新提交并开始构建。关于合并冲突：该项目将所有个性化配置都抽离到了环境变量中，直接同步上游代码通常不会产生任何合并冲突。常见问题部署成功，网页却打不开，某些操作报错？如何排查问题？ 如果部署过程没报错，但访问时出现错误（如 500 错误或白屏），通常按以下步骤排查：检查控制台：按下 F12 打开浏览器开发者工具，查看 Console 标签页是否有报错信息。查看实时日志：在 Cloudflare Dashboard 进入对应的 Worker 项目，点击 Observability (观测) -> Live。保持该页面打开的同时访问你的博客，即可捕获实时的报错日志，通常能直接看到是哪个环境变量缺失或配置错误。检查环境变量：绝大多数打不开的情况都是因为环境变量未正确设置。构建时变量 vs 运行时变量有什么区别？ 由于该项目是全栈项目，环境变量的使用场景有所不同：构建时变量：由 VITE_ 前缀开头。这些变量会在项目编译打包时「硬编码」进客户端脚本中。如果这些变量配置错误，必须重新触发部署构建才能生效。运行时变量：服务器端代码在运行时读取。这些变量通常在服务端执行逻辑中起作用。 不同方案下的配置方式：方案一 (GitHub Actions)： 你只需要在 GitHub 仓库的 Settings -> Secrets and variables -> Actions 中统一配置所有的 Secrets 和 Variables。部署流水线会自动处理它们的归类。方案二 (Cloudflare Dashboard)：构建时变量：在连接 GitHub 仓库初期的「高级选项」中配置；若项目已创建，可在 Worker 的 Settings -> Build -> Variables 中配置。运行时变量：在 Worker 的 Settings -> Variables and Secrets 中配置。如何配置统计功能？ 系统内置了浏览量统计功能。 此外，你还可以选择使用 Umami 进行客户端埋点统计，只需设置 UMAMI_SRC 和 VITE_UMAMI_WEBSITE_ID： UMAMI_SRC=https://cloud.umami.is VITE_UMAMI_WEBSITE_ID=your-website-id 发布了文章，为何前台不显示出来？ 只有当你把状态改成"已发布"以及发布时间早于当前时间的情况下，发布按钮才会调用后台任务把文章发布到前台 如果发布时间在未来，则后台任务会在未来时间点执行对于已经发布的文章，我想下架它怎么办？ 把状态从"已发布"改成"草稿"，发布按钮就会变成下架按钮部署问题请前往Issues(https://github.com/du2333/flare-stack-blog/issues)寻找相关问题，或者创建新的Issue 如何改善国内的访问速度？ 首先不管你以什么方式获取优选的ip还是cname，做好你的博客域名的DNS解析之后，假设你的博客域名是blog.example.com，使用路由方式接管worker流量，wrangler.jsonc里可改成： { "routes": [{ "pattern": "blog.example.com/*", "zone_name": "example.com" }] } 使用仓库内置 GitHub Actions 部署时，不必手动改 wrangler.jsonc：默认：custom_domain 设置仓库变量（非机密） ROUTE=1：自动切到 routes 路由模式 pattern 自动使用 ${DOMAIN}/* zone_name 默认从 DOMAIN 推导；如有子域单独托管场景，可额外设置 ZONE_NAME