上线与运维

部署到 Cloudflare Workers

使用 city deploy 把 City 项目部署到 Workers + D1。

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

如果你只是想理解 City 怎么接入 Workers 和 D1,先读 Cloudflare Workers。这一页只讲上线步骤:city.json、本地创建、本地部署、D1、admin key、env、OAuth callback 和健康检查。

前置条件

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

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

city deploy

1. 创建 City 项目

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

mkdir my-city
cd my-city
city create .

city create . 会交互式询问 City 名称和部署目标,并生成项目骨架:

  • city.json
  • src/index.ts
  • package.json
  • tsconfig.json
  • .env.example

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

{
  "type": "city",
  "name": "my-city",
  "target": "cloudflare-workers"
}

type 表示这是一个 City 项目,target 表示部署目标。当前支持 cloudflare-workers,也就是部署到 Cloudflare Edge Worker。入口文件、D1、binding、wrangler 配置都由 city createcity deploy 按 target 约定生成,不写进 city.json

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

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

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

2. 部署当前目录

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

city deploy

如果 city.jsontargetcloudflare-workerscity deploy 会自动检查 Cloudflare 登录态。没有登录时会唤起 Wrangler 登录;已经登录但 Cloudflare 无法自动返回 account 时,会提示你刷新登录,或输入一次 Cloudflare account id。输入的 account id 会保存到项目 .env,后续部署会自动复用。

也可以显式传目录:

city deploy ./my-city

3. 本地部署参数

常用本地参数可以写在项目目录的 .env

CITY_D1_DATABASE_NAME=my-city-db

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

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

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

4. Dry-run

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

city deploy --dry-run

如果部署别的目录:

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

5. 部署过程

city deploy 会执行这些步骤:

  • 读取目标目录的 city.json
  • 加载目标目录的 .env
  • 根据 city.json.target 检查目标平台登录态;Cloudflare Workers 会自动唤起 Wrangler 登录或引导选择 account
  • 如果 package.json 有 build,执行 pnpm build
  • 如果 package.json 有 typecheck,执行 pnpm typecheck
  • cloudflare-workers target 按 CITY_D1_DATABASE_NAME 查找 D1;不存在时自动创建
  • 临时生成 Wrangler 配置,不写入项目目录
  • 执行 wrangler deploy --config <generated-wrangler.toml>
  • 把 D1 database name 等部署结果写回项目 .env
  • 自动把部署出来的 Worker URL 注册成当前 City server
  • 在传入 --verify 时请求 Worker /health

.env 是本地部署绑定文件,不应该提交到 Git。city.json 仍然只保留可提交的项目声明。

6. 官方 edge 参考项目

Downcity 仓库里的参考项目是 cities/edge

city deploy cities/edge --verify

参考实现位于 cities/edge/src/index.ts

7. 初始化 City

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

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

返回大致如下:

{
  "ok": true,
  "services": ["env", "towns", "accounts", "balance", "payment", "usage", "payment.stripe", "ai"]
}

8. 取回 admin key

City 首次启动时会把 DOWNCITY_CITY_ADMIN_SECRET_KEY 写入自己的 env 表。Workers + D1 部署下,可以从远程 D1 查询:

npx wrangler d1 execute my-city-db --remote \
  --command "SELECT value FROM env WHERE key='DOWNCITY_CITY_ADMIN_SECRET_KEY'"

请把这个 key 存在可信位置。它是 Admin City、Town CLI 或直接调用 admin HTTP 接口时使用的管理凭证。

9. 写入 provider 和 service env

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

示例:

curl -X POST https://my-city.<your-subdomain>.workers.dev/v1/env/upsert \
  -H "Authorization: Bearer <admin_secret_key>" \
  -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 签名密钥
STRIPE_SUCCESS_URL可选,Checkout 成功后的默认跳转地址
STRIPE_CANCEL_URL可选,Checkout 取消后的默认跳转地址
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. 验证

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

city deploy --verify-only

也可以手动检查:

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

更新部署

修改代码后:

city deploy --verify

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