上线与运维

部署到 Cloudflare Workers

使用 fed deploy 把 Federation 项目部署到 Workers、D1、Queue 和 R2。

这页是 Federation 项目部署到 Cloudflare Workers 的正式操作路径。

如果你只是想理解 Federation 怎么接入 Workers,先读 Cloudflare Workers。这一页只讲上线步骤:federation.json、本地创建、本地部署、D1 / Queue / R2、交互式管理员配置、env、OAuth callback 和健康检查。

前置条件

  • 一个 Cloudflare 账号
  • 已经在项目里安装依赖

Downcity 不会在 git push 后自动部署 Worker。部署是显式动作:

fed deploy

1. 创建 Federation 项目

开发者通常从一个空目录开始:

mkdir my-city
cd my-city
fed create . --template cloudflare-workers

fed create . --template cloudflare-workers 会询问 Federation 名称并生成 Worker 项目骨架:

  • federation.json
  • src/index.ts
  • package.json
  • tsconfig.json

生成后的 federation.json 只保存项目基本信息:

{
  "schema": 1,
  "type": "federation",
  "id": "fed_example",
  "name": "my-city",
  "entry": "src/index.ts",
  "deployment": {
    "target": "cloudflare-workers",
    "resources": {
      "d1": {
        "type": "d1",
        "binding": "DB",
        "name": "my-city-db"
      },
      "queue": {
        "type": "queue",
        "binding": "DOWNCITY_QUEUE",
        "name": "my-city-queue"
      },
      "storage": {
        "type": "r2",
        "binding": "DOWNCITY_STORAGE",
        "name": "my-city-storage",
        "public_url_prefix": "https://images.example.com"
      }
    }
  }
}

id 是不依赖路径的 Fed 身份,deployment.target 表示部署目标。entrydeployment.resources 是可提交的部署意图;D1 database id、Cloudflare account、Worker URL 和 Wrangler 配置由 fed deploy 处理。

如果项目模板已经在 Git 仓库里,先用 fed create 拉到本地:

fed create my-city --template https://github.com/example/my-city.git
cd my-city

fed deploy 不直接部署远程 URL。它只部署本地 Federation 项目,这样 .env 和部署结果有明确归属。

2. 部署当前目录

在 Federation 项目目录里直接执行:

fed deploy

如果 federation.jsondeployment.targetcloudflare-workersfed deploy 会自动检查 Cloudflare 登录态。没有登录时会唤起 Wrangler 登录;account id 保存在系统级 Federation registry,后续部署自动复用。

也可以显式传目录:

fed deploy ./my-city

3. 资源配置

Cloudflare Workers 目标当前支持三类资源:

{
  "deployment": {
    "target": "cloudflare-workers",
    "resources": {
      "d1": {
        "type": "d1",
        "binding": "DB",
        "name": "my-city-db"
      },
      "queue": {
        "type": "queue",
        "binding": "DOWNCITY_QUEUE",
        "name": "my-city-queue"
      },
      "storage": {
        "type": "r2",
        "binding": "DOWNCITY_STORAGE",
        "name": "my-city-storage",
        "public_url_prefix": "https://images.example.com"
      }
    }
  }
}

如果没有显式配置 D1 / Queue,fed deploy 会根据 federation.json.name 使用默认名称 ${name}-db${name}-queue。Storage 只有在 deployment.resources.storage 存在时启用。

部署时会复用同名 D1、Queue 和 R2 bucket;没有同名资源且不是 --dry-run 时会自动创建。D1 database id 是 Cloudflare 部署状态,不会写回项目配置。

Cloudflare account 不属于 Federation 项目配置。fed deploy 会优先复用 Wrangler 登录态;只有 Cloudflare 无法自动识别 account 时,才会引导你输入一次并保存到本地 fed CLI 状态。

也可以部署时临时传入 account id:

fed deploy --account-id <your-cloudflare-account-id>

4. Dry-run

正式发布前先检查 bundle 和 Wrangler 配置:

fed deploy --dry-run

如果部署别的目录:

fed deploy ./my-city --dry-run

5. 部署过程

fed deploy 会执行这些步骤:

  • 读取目标目录的 federation.json
  • 根据 federation.json.deployment.target 检查目标平台登录态;Cloudflare Workers 会自动唤起 Wrangler 登录或引导选择 account
  • 如果不是 --dry-run,先把项目 package.json.version 自动做一次 patch 自增
  • 如果 package.json 有 build,执行 pnpm build
  • 如果 package.json 有 typecheck,执行 pnpm typecheck
  • cloudflare-workers target 按 deployment.resources.d1.name 查找 D1;不存在时自动创建
  • deployment.resources.queue.name 查找 Queue;不存在时自动创建
  • 如果声明了 deployment.resources.storage,按对应名称查找 R2 bucket;不存在时自动创建
  • 临时生成 Wrangler 配置,不写入项目目录
  • 执行 wrangler deploy --config <generated-wrangler.toml>
  • 请求 Worker /health 完成 Federation 系统表和默认 key 初始化
  • 首次初始化或使用 --admin-reset 时交互式要求输入管理员凭证
  • 通过部署权限把密码摘要写入 D1,并请求 /v1/admin/login 验证
  • 把 Worker URL、部署状态、管理员 ID 和有期限的 Session Token 登记到本地 Federation registry,但不修改当前 active Federation
  • 在传入 --verify 时请求 Worker /health

部署输出会按阶段汇总显示:ProjectVersionBuildTypecheckD1 DatabaseQueueStorageWranglerDeploymentFederation Registry

downfed 没有默认 Federation。部署完成后,新实例会出现在 downfed 列表中,但只有用户明确打开它时才会写入 active_server_url

federation.json 只保留可提交的项目声明。业务密钥、provider keys 和 service env 应该写入 Federation 自己的 env 表,不写入 federation.json

fed deploy --dry-runfed deploy --verify-only 不会修改项目版本号。

6. 开发者 edge 快捷示例

Downcity 仓库里保留了 templates/edgefed 作为开发者快捷示例:

fed deploy templates/edgefed --verify

这个示例适合本地实验和自定义部署。Downcity 官方私有生产 Worker 实现维护在公开仓库之外。

7. 初始化 Federation

部署完成后,请求一次 /health。这会让 Worker 启动 Federation,并创建内置的 env / cities 表。

curl https://my-city.<your-subdomain>.workers.dev/health

返回大致如下:

{
  "ok": true,
  "services": ["env", "cities", "bureaus"]
}

8. 管理员登录

首次 fed deploy 时,Downcity 会交互式要求输入管理员 ID、密码和确认密码。密码至少 12 个字符,D1 只保存 PBKDF2 摘要。遗失凭证时运行 fed deploy --admin-reset;该操作需要部署权限,会撤销全部旧管理员 Session,并要求输入新凭证。非交互环境中的 --yes 只确认破坏性重置,不会跳过凭证输入。

部署后,fed web、管理员工作区和 fed query 都通过 /v1/admin/login 登录,并使用有期限的管理员 Session Token。远端 Session Token 不会下发到浏览器,只保留在本地 CLI BFF 或 registry 中。

9. 写入 provider 和 service env

Provider API key 和服务密钥应该写入 Federation 自己的 env 表,不应该进入公开客户端。

示例:

curl -X POST https://my-city.<your-subdomain>.workers.dev/v1/env/upsert \
  -H "Authorization: Bearer <admin_session_token>" \
  -H "Content-Type: application/json" \
  -d '{"key":"DEEPSEEK_API_KEY","value":"sk-..."}'

常见 key:

Key用途
DEEPSEEK_API_KEYedge 快捷示例默认使用的 provider key
STRIPE_SECRET_KEY创建 Stripe Checkout 的 API key
STRIPE_WEBHOOK_SECRETStripe webhook 签名密钥
DOWNCITY_CITY_BASE_URLCity 对外访问地址,用于生成支付结果页
CREEM_API_KEY创建 Creem Checkout 的 API key
CREEM_PRODUCT_IDCreem 托管 Checkout 使用的一次性、含税支付 product
CREEM_CURRENCYCreem product 的币种,必须与产品实际币种一致
CREEM_WEBHOOK_SECRETCreem webhook 签名密钥;缺失时 Provider 不可用
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET可选,Google OAuth 登录
WECHAT_CLIENT_ID / WECHAT_CLIENT_SECRET可选,微信网站应用登录

10. 配置 OAuth callback

如果你开启 OAuth 登录,需要把 provider 的 callback URL 配成 Worker 对外地址:

https://my-city.<your-subdomain>.workers.dev/v1/accounts/oauth/callback

callback 域名必须和用户实际访问的公开域名一致。如果之后切到自定义域名,也要同步更新 OAuth provider 里的回调地址。

11. 验证

如果当前已经连接过 Federation,可以只执行健康检查:

fed deploy --verify-only

也可以手动检查:

curl https://my-city.<your-subdomain>.workers.dev/
curl https://my-city.<your-subdomain>.workers.dev/health

更新部署

修改代码后:

fed deploy --verify

运行时 env 保存在 D1 里,所以重新部署 Worker 不会丢失 provider key、OAuth secret、city、余额、usage 记录或 Stripe 支付记录。