从零搭建:用 Cloudflare Pages 托管自己的博客

2026-10-05 · 部署实践 · 约 12 分钟

不买域名、不租服务器、不用 Git。能装 Python 的电脑 + 一个 Cloudflare 账号, 就能把博客发到公网,而且换电脑照样能更新。

这篇文章记录的是一次真实的迁移:把博客从某个托管平台搬到 Cloudflare Pages。 过程中撞了三个坑,每一个都表现为「部署显示成功,但网站打不开」—— 排查花了很久,所以把成因和验证方法都写下来。

为什么是 Cloudflare Pages

静态博客的托管选择不少,最后选 Cloudflare Pages 是因为它在几个关键点上 没有额外成本:

项目情况
域名免费分配 <项目名>.pages.dev,不需要买
备案不需要
HTTPS自动配置并续期
费用个人博客用量在免费额度内绰绰有余
文件数上限20000 个(本站 19 个)
单文件上限25 MiB(本站最大约 1.2 MB)

它有两种接入方式:Git 集成(连 GitHub 仓库,push 自动构建) 和 Direct Upload(本地文件直接上传)。

⚠️ 选之前要想清楚

Direct Upload 项目创建后无法切换回 Git 集成,这是 Cloudflare 的平台限制。选错了只能新建项目。

本文走 Direct Upload 路线,因为它不需要 GitHub 账号、不需要配 SSH、 不需要装 Node.js——换电脑只要一个 Token。

准备:账号与密钥

1. 注册 Cloudflare 并验证邮箱

注册很直接,但有一点容易漏:邮箱必须完成验证, 否则后续 API 调用会失败。记得检查垃圾邮件夹。

2. 创建一个 API Token

Token 相当于一把专用钥匙,让脚本能往你的账号里传文件。 路径是:右上角头像 → My Profile → API Tokens → Create Token。

权限只需要一项:

✅ 唯一必需的权限

Account → Cloudflare Pages → Edit

用「Edit Cloudflare Workers」模板会附带一堆 Workers / KV / R2 / Containers 权限,这个场景一个都用不上,但不影响使用。

创建完成后页面会显示一串字符,只显示这一次,立刻复制。

Token 该怎么放

  • 不要贴在聊天记录、笔记、公开仓库里——它等同账号权限
  • 建议只建一个专用于此博客的 Token,出问题能单独吊销
  • 存到系统配置目录,不要放在项目文件夹里—— 那样打包或分享项目时会顺手泄露

部署:三步 API 流程

Cloudflare 的 Direct Upload 实际上是三个接口串起来的。 理解这个流程,出问题时才知道去哪一步找原因。

  1. 拿一个临时上传令牌 GET /accounts/{账号}/pages/projects/{项目}/upload-token

    返回一个 JWT,只用于下一步传文件。它和你的 API Token 是两回事, 有效期很短。

  2. 把文件传到资源库 POST /pages/assets/upload

    注意这个路径里没有账号 ID,用上一步的 JWT 认证。 每个文件以「内容哈希 → 文件内容」的形式提交。

    传完再调一次 upsert-hashes 登记哈希, 这样下次部署能跳过已上传的文件。这步失败不影响本次部署。

  3. 创建部署 POST /accounts/{账号}/pages/projects/{项目}/deployments

    这一步换回你自己的 API Token。提交一个清单 (每个路径对应哪个哈希)+ 分支名,平台据此把资源组装成一次部署。

完成后会返回两个地址:一个是本次部署的专属地址(带一段短哈希), 另一个是稳定的生产域名 <项目名>.pages.dev。

验证时用哪个地址

生产域名生效有几十秒延迟,刚部署完可能还是旧的或 404。 判断部署是否成功,看专属地址更可靠。

三个坑:都表现为「成功但打不开」

下面每一条都会让接口返回 success: true、部署记录显示 success,但访问任何路径都是 404。 这也是这次排查最费时间的地方——错误信号具有误导性。

坑一:文件哈希不是 SHA-256

第一反应当然是用 SHA-256 算文件哈希。而 Cloudflare 用的是 BLAKE3,而且哈希的输入还不是文件本身:

blake3( base64(文件内容) + 扩展名 ).hex()[:32]

三个细节缺一不可:算法是 BLAKE3;输入是 base64 编码后的内容再拼上 扩展名(不含点,如 html);最后取前 32 个 十六进制字符。

⚠️ Python 标准库没有 BLAKE3

hashlib 只有 blake2,没有 blake3。 所以要自己实现一个(或者引入依赖)。 实现完必须用官方向量验证——哈希算错了,同样表现为全站 404。

坑二:清单的键必须带前导斜杠

清单是「路径 → 哈希」的映射。直觉会写成 "index.html", 但必须写成 "/index.html"。

{"/index.html": "哈希值", "/about.html": "哈希值"}   ← 正确
{"index.html": "哈希值",  "about.html": "哈希值"}   ← 全站 404

这条最隐蔽:接口照样成功,部署记录照样成功,没有任何报错。

坑三:一个不存在的接口会「假装成功」

我一开始把取上传地址的接口写成了 /pages/projects/{项目}/upload。 它根本不存在——但 Cloudflare 不会返回 404, 而是兜底返回了项目对象。

结果就是:响应里 success 是 true, 但拿不到想要的字段,程序抛 KeyError。 正确路径是 /upload-token。

排查这类问题的最快办法

用官方 CLI wrangler 成功部署一次,把它当基线, 再对比自己的实现哪里不一样。这三个坑都是这样定位出来的。

以后怎么更新

内容改完之后跑一次部署脚本,约 20 秒上线。 生产域名永远不变,所以你分享出去的链接不会失效。

python deploy_cf.py deploy

脚本会自动完成:检查文件完整性 → 查账号 → 建项目(若不存在) → 取令牌 → 传资源 → 创建部署 → 打印网址。

⚠️ 别以「部署成功」为终点

因为上面那三个坑的存在,脚本输出的成功不等于线上可用。 改完后一定实际访问一次线上页面,而且要把主要内链都点一遍—— 只看首页会漏掉「某个文件被排除规则漏传」这类问题。

换电脑怎么办

这是这套方案真正的价值所在。

很多部署方案把配置和状态绑定在本地:某台电脑上的某个目录、某个配置文件。 换一台电脑,这些全都不认识你了,得从头配一遍—— 而托管平台往往只认「原来那台机器」,于是链接就保不住了。

这里的做法是:把状态全部推到云端。 项目在 Cloudflare 上,Token 是账号级的,本地只剩「站点文件 + 一个脚本」。

所以在新电脑上只需要:

  1. 复制站点文件夹过来

    或者从网盘/仓库拉取,只要文件齐全就行。

  2. 保存一次 Token

    运行 python save_token.py,粘贴 Token。 存在系统配置目录,不会随项目文件夹被复制走。

  3. 部署

    python deploy_cf.py deploy。 因为项目已经在云端存在,脚本会直接复用它, 链接保持完全一致。

✅ 关键点

本地不需要装 Git、Node.js 或 wrangler, 也不需要任何部署凭据文件(除了那个 Token)。 只要能跑 Python 3.8+ 就能更新站点。

Windows 上还会遇到一个坑

如果你的电脑没单独装过 Python,在命令行敲 python 可能看到这句话:

Python was not found; run without arguments to install from the
Microsoft Store, or disable this shortcut from Settings > Apps >
Advanced app settings > App execution aliases.

这不是 Python 坏了,是你点到了一个假的 Python。 Windows 预置了两个占位符(其实是指向微软商店的跳转器): AppData\Local\Microsoft\WindowsApps\python.exe。

更麻烦的是:用 where python 查找时,它会 优先找到这个假货并返回成功。所以脚本里判断 Python 是否存在,不能只用 where, 必须实际跑一次验证:

python -c "import sys"    # 跑不通说明是假占位符

解决办法有三个:直接指定真实 Python 的完整路径; 在「设置 → 应用 → 高级应用设置 → 应用执行别名」里关掉那两个开关; 或者去官网装一个真的 Python(安装时记得勾选 Add Python to PATH)。

这套方案不适合什么

说清楚边界比只讲好处更有用:

  • 不接受手动上传。 每次更新都要跑一次命令。 如果你想要「push 就自动部署」,那应该用 Git 集成路线, 代价是要配 GitHub 仓库。注意这是二选一,创建时就得决定。
  • 没有版本历史。 每次部署覆盖上一次, 平台保留部署记录但内容以最后一次为准。想要完整历史就得靠 Git。
  • 不支持需要后端的场景。 静态文件可以, 需要数据库或服务端逻辑就得用别的方案。

小结

静态博客托管其实不复杂,难点集中在几个不直观的细节上—— 哈希算法、清单格式、以及一个会「假装成功」的接口。 这些细节都不会给出明确的错误提示,只能靠理解流程和实际验证来发现。

而「换电脑可用」这件事,本质上不是技术问题,是架构选择: 把状态放在云端,本地只留可复制的文件和一把钥匙, 迁移就退化成「复制文件夹 + 粘贴一次 Token」。