部署设置
把两个站点部署到 Cloudflare
英文版本 为准,本文供参考。本教程沿用仓库现有的 GitHub Actions → Cloudflare Workers Static Assets 发布流程。令牌和工作流重跑参考于 2026-09-18 核对。账号配置和线上部署结果仍需在实际操作时验证。
操作顺序是:准备账号和参数 → 通过 GitHub 发布 → 检查 workers.dev 临时网址 → 绑定自定义域名 → 验收线上站点。切换成功前保留原来的托管服务,以便恢复。
1. 准备账号,确定名称和网址
需要拥有 GitHub 仓库管理员权限、目标 Cloudflare 账号内的 Worker 部署及域名管理权限。如果要修改 nameservers,还需要登录域名注册商。GitHub 仓库应当已经有获批的 main 分支及 .github/workflows/ci.yml。如果尚无 main,先与所有者完成仓库基线初始化;不要临时直推 main 绕过 PR 规则。
先确定并记下以下值。下表是贯穿教程的填写示例,不代表这些名称或域名已在线上配置。 如果实际使用其他名称,后续所有步骤都要同步替换。
| 用途 | 示例 | 填写位置 |
|---|---|---|
| 个人主站 Worker | donnyguo-portfolio | GitHub 的 PORTFOLIO_WORKER_NAME |
| 工程日志 Worker | donnyguo-logs | GitHub 的 LOG_WORKER_NAME |
| 主站正式网址 | https://donnyguo.com | GitHub 的 PORTFOLIO_SITE_URL |
| 日志正式网址 | https://logs.donnyguo.com | GitHub 的 LOG_SITE_URL |
| 可选的主站别名 | www.donnyguo.com | 主站 Worker 的第二个自定义域名 |
手机等窄屏设备上,可以左右滑动宽表格查看全部列。
两个 Worker 名称必须不同;使用 1–63 个小写字母、数字或连字符,首尾使用字母或数字。站点网址使用 HTTPS,只填来源地址,不带路径、查询参数或片段。生产脚本会拒绝 localhost、example.com 等保留示例域名。
主站由 Astro 构建到 dist/portfolio/,工程日志由 Hugo 构建到 dist/logs/。两个站点各自的 / 是英文,/zh/ 是中文。它们部署成两个 Worker,不是同一次部署的两个子目录。日志站会公开仓库指南与变更记录,上传前要确认这些内容适合公开。
本教程使用 wrangler.portfolio.json 和 wrangler.logs.json 已配置的 Workers Static Assets。不要另建 Pages 项目,也不要为同一发布再接入一套 Cloudflare Git 自动构建。参见静态资源说明
。
本步完成标志:所需权限、main 上的工作流均已具备,两个 Worker 名称及正式网址已确定。
2. 先在本地验证待发布版本
本地验证用来提前发现构建或内容错误,生成与 CI 发布时相同类型的静态文件;本地检查成功不会修改线上网站。
在含有 package.json 的仓库目录运行命令。先按开发指南
启用固定版本的 Node.js、pnpm、Go 和 Hugo;如需修改文件,使用独立功能 worktree。本步不需要 Cloudflare 令牌。
预期版本分别为 Node.js 26.8.2、pnpm 12.4.1、Go 1.27.1、Hugo Extended 0.166.0。Linux 安装浏览器时改用 pnpm exec playwright install --with-deps chromium。
在当前终端设置正式构建网址。先替换示例值,再运行验证:
pnpm verify 应通过类型与内容测试、两站构建、产物检查及浏览器测试;两个 dry run 都应成功退出,并存在 dist/portfolio/index.html 和 dist/logs/index.html。Dry run 不会上传,也不能验证令牌、DNS 或 HTTPS。本地终端变量或 .env 不会同步到 GitHub,后面第 6 步仍须单独填写。需要启动本地预览或停止服务时,按开发指南操作。
本步完成标志:使用预定正式网址时,验证和两次 dry run 均通过。这些结果只代表本地检查,不能作为线上验收结果。
3. 配置期间先关闭部署
在 GitHub 仓库打开 Settings → Actions → General,确认 Actions 已启用,然后:
- 打开 Settings → Secrets and variables → Actions → Variables。
- 点 New repository variable,在 Name 填
DEPLOY_ENABLED,在 Value 填false,点 Add variable。如果已有这个变量,点编辑按钮,把值保存为false。 - 第 5–6 步的密钥和变量准备好之前,保持
false;关闭部署期间仍可运行检查。
值不带外层引号。修改变量不会自动启动工作流。代码或文档改动按协作流程
操作:在功能分支修改,创建 PR,最新提交的 CI / checks 通过后再合并。
本步完成标志:Actions 已启用,仓库变量 DEPLOY_ENABLED 为 false。
4. 准备 Cloudflare 账号和域名 DNS
账号和临时网址
在 Cloudflare 选择准备部署的账号,打开 Workers & Pages,完成首次使用 Workers 的账号设置,确认账号已有 workers.dev 子域名。记下概览显示的账号子域名;已经设置过的无需更改。每个 Worker 的临时网址形如 https://WORKER_NAME.ACCOUNT_SUBDOMAIN.workers.dev,这些网址可以被公开访问。参见 workers.dev 设置
。
不必先手动创建两个空 Worker:首次 CI 上传会按指定名称创建。如果账号里已经有同名 Worker,先确认它们就是这两个站点,因为部署会更新同名资源。在第 7 步确认新站产物正常前,让正式域名继续指向原来的服务。
域名区域
Nameservers 决定“由谁回答这个域名应该去哪里”。改成 Cloudflare 的 nameservers,是让 Cloudflare 接管 DNS 解析,还没有把网站切换到新 Worker。第 8 步才把具体主机名绑定到对应 Worker,所以接入 DNS 和切换网站是两步操作。
如果域名已经在这个 Cloudflare 账号内显示为 Active,保留现有 nameservers,跳过下面的迁入步骤。否则:
- 私下保存或导出现有 DNS 记录,记下原 nameservers 和托管目标。包含博客等现有子域名,以及邮箱的 MX/TXT 记录。
- 在 Cloudflare 账号的域名接入流程中添加域名,检查或导入 DNS 记录。自动扫描可能漏项;此时保留原网站的解析目标。
- 如果注册商处启用了 DNSSEC,先按官方迁移说明处理,再切换 nameservers。普通完整接入流程应先停用旧 DNSSEC 委派,待 Cloudflare 激活后再启用其 DNSSEC。
- 登录域名注册商,把权威 nameservers 改为 Cloudflare 分配的准确两项,等待 Cloudflare 显示 Active。把下面命令中的域名替换为自己的域名,执行
dig +short NS donnyguo.com;传播完成后应与分配的 nameservers 一致。
这是迁移 DNS 托管,无需转移域名注册商。全程保留邮箱及其他服务。参见 Cloudflare 域名接入步骤 。如果不确定账号归属或某条同名记录的用途,先核实,再改线上 DNS。
本步完成标志:账号已有 workers.dev 子域名,正式域名在同一账号内为 Active,原路由及 DNS 设置已有私下备份。
5. 把 Cloudflare 凭据保存到 GitHub
创建或核对令牌
- 在 Cloudflare 选择目标账号,从 Workers & Pages → Account Details 复制 Account ID。使用账号 ID,不是 Zone ID;参见查找位置 。
- 打开 Manage Account → Account API Tokens → Create Token。创建账号令牌需要该账号的 Super Administrator 权限。在 Permission policies 中选择 Custom → Edit Cloudflare Workers,名称填
github-static-sites。 - 资源范围限定为部署账号;模板要求选择域名资源时,限定为目标域名。保留模板中的 Worker 权限,确认包含 Account → Workers Scripts → Edit 和 Account → Account Settings → Read。只有 Pages 或 DNS 权限不能完成这里的部署。
- 点 Continue to summary → Create Token,把令牌值直接复制到下面的 GitHub secret 中。不要放进源码、普通变量、日志或截图。
如果策略编辑器显示 Specified Domains → donnyguo.com,这条策略只授予域名权限。点 Add policy,把新策略的资源范围设为部署账号,在 Search for permission groups 中分别搜索下表两项,选择对应权限后保存策略。它们应放在账号策略中,不能只配置域名策略。不需要点 Select all。
| 搜索内容 | 选择权限 | 用途 |
|---|---|---|
Workers Scripts | Edit(API 权限列表称为 Write) | 上传和部署 Worker |
Account Settings | Read | 读取账号设置 |
上述操作依据 Cloudflare 的 CI 认证说明 和账号令牌说明 。已有有效部署令牌可以继续使用。
如果使用 My Profile → API Tokens 中的个人令牌,在该页面使用 Edit Cloudflare Workers 模板。除账号权限外,保留 User → User Details → Read 和 User → Memberships → Read,供 Wrangler 查询用户和账号诊断信息。这些 User 权限适用于个人令牌,不要在账号令牌表单中寻找。参见个人令牌模板权限
。遇到 Unable to get membership roles 时,先按第 11 步定位,再调整权限。
添加或更新两个密钥
在 GitHub 打开 Settings → Secrets and variables → Actions → Secrets。按下表逐项点 New repository secret,填写 Name 和 Secret,再点 Add secret。
| Name | Secret |
|---|---|
CLOUDFLARE_API_TOKEN | Cloudflare API 令牌值 |
CLOUDFLARE_ACCOUNT_ID | 同一个部署账号的 Account ID |
已有同名密钥时,点编辑按钮,粘贴当前值,再点 Update secret。GitHub 不会显示已保存的值。如果替换令牌,先验证上传成功,再确认旧令牌没有其他用途后撤销它。参见 GitHub 仓库密钥 。
本步完成标志:两个名称都出现在 Repository secrets 下,令牌账号范围与保存的 Account ID 一致。实际权限在上传时验证。如果更新后没有效果,按第 11 步检查密钥优先级。
6. 填写 GitHub 仓库变量
进入 Settings → Secrets and variables → Actions → Variables → New repository variable,按下表逐项保存。已经存在的部署开关直接编辑,不要另起名称。
| 名称 | 示例值 | 作用 |
|---|---|---|
PORTFOLIO_WORKER_NAME | donnyguo-portfolio | 接收 dist/portfolio/ 的 Worker |
LOG_WORKER_NAME | donnyguo-logs | 接收 dist/logs/ 的 Worker |
PORTFOLIO_SITE_URL | https://donnyguo.com | 主站构建时使用的 canonical 网址 |
LOG_SITE_URL | https://logs.donnyguo.com | Hugo 构建时使用的正式 base URL |
DEPLOY_ENABLED | 暂时填 false | 只有精确值 true 才会启用部署 |
输入原始值,不要带外层引号。五项都保存为 repository variables(仓库变量),让构建和部署任务都能读取。参见 GitHub 配置变量 。
两个 Worker 名称会覆盖 Wrangler 文件里的示例名称。两个网址变量影响生成 HTML 及 Hugo 链接,不会自动创建 DNS 记录或绑定域名。后续改变正式网址时,需要重新构建,并单独调整域名配置。
本步完成标志:五个仓库变量均与计划一致,仓库的两个 secret 也已保存。
7. 启动部署,确认两站上传成功
完成第 5–6 步后,按以下操作发布当前 main 上已获准发布的内容。两个站点都会公开,包括工程日志。
打开部署开关
- 打开 Settings → Secrets and variables → Actions → Variables。
- 找到
DEPLOY_ENABLED,点编辑按钮,把 Value 改为true,点 Save variable。
找到当前 main 的工作流并重跑
- 打开仓库 Code 标签,选择 main 分支,打开最新一条提交,记下 commit SHA(提交编号)。
- 打开 Actions,左侧选择 CI,筛选 Branch → main 和 Event → push。打开提交编号与刚才 Code 页面一致的那条任务。PR 检查任务不能发布。
- 如果任务仍在运行,等它结束。已结束的任务,在右上角点 Re-run all jobs;如果任务失败,先打开 Re-run jobs → Re-run all jobs。在确认框点 Re-run jobs。它会重新构建和检查两个站点,再上传。参见 GitHub 重跑入口 。
- 如果没有对应的 push 任务可重跑,打开 Pull requests,进入已获准合并的功能 PR,确认最新提交的 Checks → CI / checks 已通过,再点 Merge pull request 并确认合并。返回 Actions → CI,打开新出现的 main / push 任务。如果尚无获准 PR,按协作指南 准备;不要为了触发部署直接推送 main。
单独修改开关或密钥不会启动任务。当前工作流没有手动触发器,所以没有 Run workflow 按钮。重跑会保留原提交编号;如果 main 已有新提交,改选新 main 对应的任务。
查看部署结果
- 在任务左侧的 Jobs 下打开 checks,等它通过;其中 Upload checked static sites 步骤会保存已测试的
static-sites产物。 - 回到任务概览,打开 deploy,展开 Publish checked main artifacts。任务会先下载已检查的产物,再由这个步骤先上传主站、后上传日志站。
- 确认日志最后出现
Published checked revision to: portfolio, logs。只有checks变绿、deploy被跳过,或出现Skipped: this revision is no longer main.,都不代表发布成功。上传步骤报红时按第 11 步排查。 - 在 Cloudflare 打开 Workers & Pages → donnyguo-portfolio → Settings → Domains & Routes,打开其中的 workers.dev 网址。对
donnyguo-logs重复操作,名称以第 6 步填写的值为准。如果 workers.dev 被关闭,先在此处启用再检查。 - 在主站 workers.dev 域名下访问
/、/zh/和/projects/cloud-storage/;在日志站 workers.dev 域名下访问/、/zh/和/docs/deployment/。输入路径时保留 workers.dev 域名,页面中按正式域名生成的链接在第 8 步之后检查。
本步完成标志:当前 main 的任务报告两站均上传完成,两个 workers.dev 站点都能显示预期页面。再继续第 8 步绑定正式域名。
8. 把正式域名指向 Worker
这一步会切换实际访问流量。替换任何解析记录前,先确认第 4 步的原托管服务及 DNS 备份。进入 Cloudflare 的 Workers & Pages → 主站 Worker → Settings → Domains & Routes → Add → Custom Domain,只填主机名,例如 donnyguo.com,然后确认。再到日志 Worker 中添加 logs.donnyguo.com。
Cloudflare 会为每个 Custom Domain 创建路由所需的 DNS 记录和 HTTPS 证书。等待域名及证书就绪后,打开正式 HTTPS 网址。域名输入框不要填 https://、路径或 /*。如果主机名已有 CNAME,会阻止创建;确认旧目标并保存备份后,在切换时删除这条冲突记录,随即添加 Custom Domain。其他冲突或替换提示也要与备份对照,不要删邮箱或其他博客记录。参见自定义域名官方说明
。
如果还希望 www.donnyguo.com 访问主站,在主站 Worker 上重复操作,添加这个主机名。它会成为第二个可访问的域名,不会自动跳转。在 PORTFOLIO_SITE_URL 中确定一个 canonical 正式网址;如希望 www 自动跳转到根域名,需要另行配置重定向规则。
本教程在后台管理域名绑定。当前 Wrangler 文件没有 routes;后续不要随意添加不完整的路由列表,因为由 Wrangler 管理的路由可能覆盖后台设置。若改为在配置文件管理域名,应作为明确变更处理,并在每次发布后重新检查两个域名。参见 Wrangler 路由配置
。
本步完成标志:两个正式 HTTPS 域名证书有效,分别打开正确站点;配置了 www 的,也能正常访问。
9. 验收线上结果
把下面示例替换为自己的正式网址,运行只读检查:
预期前四项输出 200,后两项输出 404。TLS 报错或状态 000 表示连接失败。如出现非预期跳转,先用 curl -I URL 查看响应再判断;错误页面即使看起来正确,返回 200 也不能算 404 验收通过。
在浏览器检查主站的 Projects、一个项目详情、Experience、中英文切换、图片和手机宽度布局。在日志站打开两种语言的指南及变更文章,跟随站内链接,并搜索页面上确实存在的词。检查 HTML 中的 canonical 是否使用预定域名;DNS 迁移后还要确认原博客和邮箱服务正常。检查公开产物不包含草稿、测试内容、原始简历或本地验收文件。
把实际 main SHA、工作流任务、公开网址及结果写入对应中英文变更日志。令牌、账号标识、DNS 备份及私密截图不要进入公开记录。没有执行的检查明确记为未验证。
10. 后续发布、重试和回滚
正常更新只需合并通过检查的 PR,main 工作流会重新构建并自动发布。生产锁让部署按顺序执行。上传前,脚本核对 main 当前 SHA;旧任务会显示 Skipped: this revision is no longer main.,不上传任何内容。即使任务显示成功,出现这句话也不代表发布了新版本。
令牌或临时上传故障修好后,先确认失败任务仍对应当前 main,然后进入 Actions → CI → 该任务 → Re-run jobs → Re-run failed jobs。构建产物保留 7 天;如果产物已丢失,或构建网址发生变化,选择 Re-run all jobs,重新构建并检查当前 main。若任务已无法重跑,通过获授权的修复 PR 触发新任务。不要重跑 PR 事件来尝试部署;GitHub 重跑会保留原事件、分支引用及 SHA。参见工作流重跑说明 。
如果 main 已向前推进,使用当前 main 的任务。两次上传不是原子操作:Release failed at logs. Already published: portfolio. 表示主站已更新而日志站没有。解决故障后重跑当前 main;两个站点都会再次尝试上传。
暂停后续自动发布时,把 DEPLOY_ENABLED 设为 false。这不会下架已发布站点、取消已经开始的上传,也不会恢复旧版本。恢复前先检查运行中或排队的任务。
如果已发布的代码或内容有问题:
- 从 main 历史和 CI 记录中确定最后正常的源码版本及有问题的变更。
- 按协作指南,从当前 main 创建回滚 worktree 和分支。若只撤回一个普通提交,可用
git revert --no-commit BAD_COMMIT_SHA准备差异,先替换占位符。合并提交需要明确选择 mainline parent,通常为-m 1;多个相互依赖的变更应先确定回滚范围。 - 检查差异,运行
pnpm verify和pnpm deploy:dry-run,再完成暂存差异确认、提交及 PR 流程。不要用破坏性 reset 或重跑旧工作流来回滚。 - 如果先前暂停了发布,在合并获批回滚 PR 前重新启用部署。检查其当前 main 发布结果,并为两站重做第 9 步验收。
如果是域名切换失败,保留新 Worker,先恢复旧站:移除受影响的 Custom Domain 绑定,在 Cloudflare 恢复这个主机名原先保存的 DNS 记录,再检查旧站 HTTPS、邮箱及博客。前提是原托管服务仍可用。除非另有完整 DNS 服务商回迁方案,否则保留正常工作的 Cloudflare nameservers;nameservers 与 DNSSEC 回迁有各自的传播及验证要求。已被外部下载的公开内容,无法靠回滚或改 DNS 收回。
11. 部署失败时怎么定位
/accounts/…/workers/subdomain 返回认证错误 10000
这个请求用于读取账号的 workers.dev 子域名。接口接受 Workers Scripts Read 或 Write 。如果令牌汇总已经列出 Workers Scripts Write,下一步应核对 CI 实际使用的令牌及目标账号,不要继续添加权限名称。
- 在目标 Cloudflare 账号重新复制 Account ID,更新 GitHub 的
CLOUDFLARE_ACCOUNT_ID密钥。不要填 Zone ID 或令牌自身的 ID。 - 确认
CLOUDFLARE_API_TOKEN填的是刚才检查权限的那枚令牌的完整值,不带引号或Bearer前缀,资源范围覆盖同一个账号。如果找不到原值,新建相同预定范围的替代令牌并更新密钥;验证成功前保留旧令牌。 - 检查任务实际使用哪份密钥。如果 deploy 任务声明了环境,打开 Settings → Environments → 对应环境 → Environment secrets,查看是否也有这两个名称。同名环境密钥会覆盖仓库密钥;如有,也要更新那里的实际生效值。参见 GitHub 密钥优先级 。没有环境密钥时,使用第 5 步的仓库值。
- 按第 7 步重跑当前 main。如果仍是同一错误,继续核对令牌状态、资源范围及限制条件与目标账号是否匹配,保留最初失败的 API 操作和错误码用于进一步定位。以实际上传成功验证,而不是仅凭权限汇总判断。
10000 能确定该请求认证失败,但不能单独区分账号 ID 错误、保存了错误令牌,还是令牌范围或限制问题。它也不能证明 DNS 有故障或尚未注册 workers.dev。
Unable to get membership roles
这是随后出现的账号成员诊断信息。个人令牌缺少 User → Memberships → Read 可能导致它;诊断账号令牌时也可能出现。上面的子域名接口不要求这项用户权限。Wrangler 4.131.1 会先输出认证错误,再运行这部分诊断,参见其错误处理源码 和成员权限诊断源码 。
在 deploy → Publish checked main artifacts 中,向上找到成员提示之前最早的 Cloudflare ERROR,按该操作排查;分享片段前遮盖账号标识。scripts/release.ts:12 是仓库上传失败后的报错包装位置;其中的 Release failed at … Already published: … 说明哪一站失败、哪些上传已经完成,不是 Cloudflare 的原始原因。
其他常见问题
| 现象 | 下一步 |
|---|---|
| 改完设置没有新任务 | 按第 7 步重跑当前 main;修改变量或密钥不会触发任务。 |
deploy 被跳过 | 确认任务是 main / push、checks 已通过,仓库变量 DEPLOY_ENABLED 精确为 true。 |
Missing deployment setting: ... | 按第 5–6 步核对密钥或变量的准确名称和位置。 |
Invalid Worker name 或 HTTPS 网址错误 | 按第 1 步格式填写,去掉引号、空格和保留示例域名。 |
| workers.dev 设置报错 | 在 Workers & Pages 完成账号子域名设置,再重跑当前 main。 |
Unable to verify main before upload 或旧版本被跳过 | 按报错恢复 GitHub API 访问,或选择当前 main;保留 SHA 校验。 |
缺少 static-sites 产物,或 Hugo 链接仍用旧域名 | 核对网址变量,对当前 main 选择 Re-run all jobs 重新构建。 |
| 只有一个站点更新 | 查看 Already published,按第 10 步恢复部分发布。 |
| 自定义域名冲突、DNS 错误或证书待生效 | 按第 8 步检查绑定、Active 区域、已备份的 DNS 目标及证书状态,并与 workers.dev 对照。 |
| 本地工具或 Chromium 错误 | 按开发指南 核对固定版本及排错步骤。 |