# 生产稳定基线 日期:2026-06-04 适用环境:`sub.tksea.top` / remote43 ## 目标 这份文档固定当前线上生产入口,防止临时验收栈、历史 patched host 或旧用户 key 被误当成生产真相。 生产稳定判断只看当前生产栈。历史 artifact、旧 OpenClaw profile、旧 key、旧端口只能作为迁移线索,不能作为生产健康结论。 remote43 只应长期保留一套生产宿主。生产宿主同时承担生产流量和受控 smoke 测试;临时宿主只能用于短期验收,验收结束后必须清理或停止,不能长期留作备用生产入口。 ## 当前生产固定点 | 层级 | 固定值 | 说明 | |---|---|---| | 公网数据面 | `https://sub.tksea.top/v1` | OpenAI-compatible 用户调用入口 | | 公网 Portal | `https://sub.tksea.top/portal/` | 用户态静态 portal | | 公网管理代理 | `https://sub.tksea.top/portal-admin-api/` | 反代到 CRM 控制面 | | 生产宿主 | `127.0.0.1:8080` | `sub2api` 主容器 | | 生产 CRM | `127.0.0.1:18190` | `crm-only-20260602_18190` | | 生产宿主容器 | `sub2api` | 当前主数据面容器 | | 生产宿主数据库 | `sub2api-postgres` | 当前主宿主 PostgreSQL | | 生产宿主 Redis | `sub2api-redis` | 当前主宿主 Redis | | 生产 CRM 二进制 | `/home/ubuntu/crm-only-20260602_18190/sub2api-cn-relay-manager-server` | 控制面进程 | | 生产 CRM 数据库 | `/home/ubuntu/crm-only-20260602_18190/sub2api-cn-relay-manager.db` | 控制面 SQLite | ## Nginx 基线 `/etc/nginx/sites-available/tksea` 必须满足: ```nginx location /portal/ { alias /var/www/sub2api-portal/; index index.html; try_files $uri $uri/ /portal/index.html; } location /portal-proxy/ { proxy_pass http://127.0.0.1:8080/; } location /portal-admin-api/ { proxy_pass http://127.0.0.1:18190/; } location /kimi/ { proxy_pass http://127.0.0.1:8080/; } location /kimi-v1/ { proxy_pass http://127.0.0.1:8080/v1/; } location / { proxy_pass http://127.0.0.1:8080; } ``` 公网生产入口不得指向: ```text 127.0.0.1:18169 127.0.0.1:18173 127.0.0.1:18191 127.0.0.1:18192 127.0.0.1:18193 ``` 这些端口属于历史 patched stack、route lab 或验证栈。它们可以用于验收,但不能接管 `sub.tksea.top` 的生产入口。 ## 健康判定 ### 无密钥健康检查 无密钥请求 `/v1/models` 返回 `401 API_KEY_REQUIRED` 是健康信号。它证明公网请求已经到达生产宿主,而不是 nginx 死 upstream。 ```bash curl -sS -i https://sub.tksea.top/v1/models ``` 预期: ```text HTTP/2 401 API_KEY_REQUIRED ``` 如果返回 `502 Bad Gateway`,优先检查 nginx upstream 是否又指回旧端口。 管理代理健康检查: ```bash curl -fsS https://sub.tksea.top/portal-admin-api/healthz ``` 预期: ```text ok ``` Portal 静态入口检查: ```bash curl -fsS -I https://sub.tksea.top/portal/ ``` 预期:`HTTP/2 200`。 ### 真实用户 smoke 生产 smoke 必须使用当前生产宿主数据库里的 active key。旧 OpenClaw profile 中保存的 key 可能来自旧宿主或旧分组,不能作为生产健康依据。 最低通过标准: 1. active key 请求 `https://sub.tksea.top/v1/models` 返回 200。 2. 模型列表包含 `gpt-5.4` 与 `gpt-5.4-mini`。 3. 同一个 key 请求 `gpt-5.4` completion,prompt 为 `reply with pong only`,返回 `pong`。 4. 同一个 key 请求 `gpt-5.4-mini` completion,prompt 为 `reply with pong only`,返回 `pong`。 2026-06-04 修复后已验证: ```text gpt-5.4 -> HTTP 200, text='pong' gpt-5.4-mini -> HTTP 200, text='pong' ``` ## 当前生产绑定基线 OpenAI 中转 self-service 链路必须保持: ```text channel 1 -> group 3 api key 11 -> group 3 account 7 -> group 3 ``` `account 7` 同时服务 subscription 分组: ```text account 7 -> group 4 ``` 2026-06-04 的修复补齐了: ```text account 7 -> group 3 ``` 没有这条绑定时,`/v1/models` 仍可能返回 200,但 `/v1/chat/completions` 会失败: ```text account_select_failed: no available accounts ``` ## 验收栈隔离规则 验收脚本可以创建临时 host、临时 group、临时 account、临时 key 和临时 CRM,但不得修改生产公网入口。 下列对象不能作为生产入口: ```text crm-verify-* route-lab-* sub2api-kimi-patched-* sub2api-patched-* remote43-kimi-patched-auto2-18169 proxy-real-host-1780026133 ``` 这些对象只用于复现、导入验收或历史 artifact 对照。它们的 PASS 不能替代当前生产 smoke。 ## 临时宿主生命周期 remote43 的默认运行策略是“单生产宿主”。除当前生产宿主外,其他 host、CRM、Postgres、Redis、route lab 或 patched stack 都视为临时资源。 临时资源创建时必须满足: 1. 不接管 `sub.tksea.top` 的公网数据面。 2. 不修改生产 Nginx 的 `/`、`/v1`、`/portal-proxy`、`/portal-admin-api` upstream。 3. 使用独立端口、独立容器名、独立数据库或独立 SQLite。 4. artifact 记录创建原因、端口、容器名和预期清理时间。 临时资源用完后必须执行清理。最低要求: 1. 停止临时 host / CRM 进程或容器。 2. 停止临时 Postgres / Redis 容器,除非同一验收批次还在使用。 3. 删除或归档临时 SSH tunnel、临时 env 文件和临时 bootstrap 文件。 4. 确认 `sudo nginx -T` 不引用临时端口。 5. 重新跑生产 smoke,确认生产宿主仍可用。 允许保留的长期资源只有当前生产基线列出的生产宿主、生产 CRM、生产数据库和生产 Redis。 如果确实需要保留某个临时栈用于复现,必须显式标注为 `do-not-route-public`,并保证它不被 Nginx 或 OpenClaw production profile 使用。 清理后检查: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' ss -ltnp sudo nginx -T | grep -nE '18169|18173|18191|18192|18193|proxy_pass' curl -sS -i https://sub.tksea.top/v1/models curl -fsS https://sub.tksea.top/portal-admin-api/healthz ``` `/v1/models` 无 key 返回 `401 API_KEY_REQUIRED` 才表示生产数据面仍指向当前生产宿主。 ## 部署脚本基线 `scripts/deploy/deploy_tksea_portal.sh` 的默认端口必须保持: ```bash REMOTE_HOST_PORT="${REMOTE_HOST_PORT:-8080}" REMOTE_CRM_PORT="${REMOTE_CRM_PORT:-18190}" ``` `deploy/tksea-portal/nginx.sub.tksea.top.conf.example` 必须和线上端口一致: ```text /portal-proxy/ -> 127.0.0.1:8080 /portal-admin-api/ -> 127.0.0.1:18190 /kimi/ -> 127.0.0.1:8080 /kimi-v1/ -> 127.0.0.1:8080/v1/ ``` 每次部署前后都要检查: ```bash sudo nginx -T | grep -nE 'location /v1|location /portal|location /portal-admin-api|location /kimi|proxy_pass' ``` 部署后必须执行: ```bash sudo nginx -t sudo systemctl reload nginx curl -sS -i https://sub.tksea.top/v1/models curl -fsS https://sub.tksea.top/portal-admin-api/healthz ``` ## 旧 Key 解释规则 旧用户 key 或旧 OpenClaw profile 失败,不直接等于生产宿主异常。先判断它是否属于当前生产宿主和当前分组。 常见旧 key 失败原因: ```text key 属于旧宿主数据库 key 未绑定 group key 绑定的 group 没有 account key 对应 subscription 已过期 key 保存于旧 OpenClaw profile key 仍指向旧模型映射 ``` 判断生产健康时,优先使用当前生产数据库生成的 smoke key,或当前生产 active key。 ## 故障分层 | 现象 | 优先判断 | 下一步 | |---|---|---| | `/v1/models` 无 key 返回 502 | nginx upstream 或宿主端口错误 | 查 `nginx -T`、`ss -ltnp`、`/var/log/nginx/error.log` | | `/v1/models` 无 key 返回 401 | 数据面入口到达宿主 | 继续用 active key 跑 `/v1/models` | | active key `/v1/models` 返回 200,但 completion 失败 | group/account/channel/upstream 问题 | 查 `account_groups`、`channel_groups`、宿主日志 | | 日志出现 `no available accounts` | group 没有可调度 account | 查并修复 `account_groups` | | 日志出现 upstream 502/503 | 上游 key/quota/供应商异常 | 查 account probe、上游直探 | | OpenClaw profile 返回 401,但 production key curl 通过 | 本机 OpenClaw key 过期或不属于当前生产宿主 | 更新 OpenClaw profile key | | remote43 上存在多套 host | 临时资源未清理 | 保留生产宿主,停止或归档临时栈 |