上线与运维

Dokploy 部署

用持久化 City 数据库把 Downcity Node 街区部署到 Dokploy。

Node 街区是 Downcity City Infra 的标准 Docker / Dokploy 部署形态。

它运行 cities/node,暴露 City HTTP API,并把 SQLite 数据保存在持久化 /data volume 里。适合给产品、应用、Agent 或内部工具提供一套长期运行的城市服务层。

Dokploy 配置

在 Dokploy 里创建应用,选择当前 Git 仓库:

配置项
部署模式Compose
Compose 文件./docker-compose.yml
Container port43127
VolumeCompose 自动创建 downcity_infra_data

Dokploy 里必须配置这两个稳定的 bootstrap secret:

DOWNCITY_CITY_ADMIN_SECRET_KEY=admin_xxx
DOWNCITY_CITY_TOKEN_SIGNING_KEY=sign_xxx

HOSTPORTDOWNCITY_CITY_DATABASE_URL 已经写在 docker-compose.yml 中:

HOST=0.0.0.0
PORT=43127
DOWNCITY_CITY_DATABASE_URL=file:/data/downcity.sqlite

/data 必须是持久化 volume。town、model、用户、session、usage、payment 和 City env 都会保存在这个 SQLite 数据库里。

域名路径

Node 街区默认监听 43127,City API 直接挂在服务根路径下:

GET  /health
POST /v1/env/upsert
GET  /v1/services
POST /v1/ai/text

如果你的域名是 https://base.example.com,产品侧 SDK 和可信后端应该使用:

base_url=https://base.example.com

如果 Stripe redirect URL 没有直接配置,可以把 DOWNCITY_CITY_BASE_URL 写入 City env,让支付页自动推导默认 success / cancel URL:

curl -X POST https://base.example.com/v1/env/upsert \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer admin_xxx' \
  -d '{"key":"DOWNCITY_CITY_BASE_URL","value":"https://base.example.com"}'

Provider Key

Provider API key 不建议写在 Dokploy env 里。部署完成后,通过 Admin API 写入 City 数据库:

curl -X POST https://base.example.com/v1/env/upsert \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer admin_xxx' \
  -d '{"key":"MOONSHOT_API_KEY","value":"your_api_key"}'

curl -X POST https://base.example.com/v1/env/upsert \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer admin_xxx' \
  -d '{"key":"DEEPSEEK_API_KEY","value":"your_api_key"}'

运行时 ctx.env.MOONSHOT_API_KEYctx.env.DEEPSEEK_API_KEY 会优先从 City 数据库读取。

验证

Dokploy 部署完成后,先验证公开服务:

curl https://base.example.com/health

只用 IP 和端口时:

curl http://1.2.3.4:43127/health

预期返回大致如下:

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

如果这里超时,说明 Dokploy 服务没有对外暴露、VPS 防火墙没放行 43127,或还没有绑定可访问的域名。

产品侧调用

产品前端和应用应该通过 @downcity/city 调用 Node 街区:

import { City } from "@downcity/city";

const client = new City({
  role: "user",
  city_url: "https://base.example.com",
  town_id: "my-town",
  user_token: "user_token",
});

可信后端应该用 Admin City 携带 DOWNCITY_CITY_ADMIN_SECRET_KEY

import { City } from "@downcity/city";

const admin = new City({
  role: "admin",
  city_url: "https://base.example.com",
  admin_secret_key: process.env.DOWNCITY_CITY_ADMIN_SECRET_KEY,
});

完整 SDK 能力继续看 User CityAdmin City