CODEX KNOWLEDGE

key.tengokukk.com OpenAI v1 网关现状与修复记录(2026-04-23)

2026/04/23 39 min read CODEX KNOWLEDGE 目录 CODEX KNOWLEDGE 类 运维执行 项目 ATRAMENTI CONSOLE 形态 记录 KEY TENGOKUKK COM OPENAI V1 网关现状与修复记录(2026 04 23)

key.tengokukk.com OpenAI v1 网关现状与修复记录(2026-04-23)

  • Canonical target: E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\20-operations-key-tengokukk-openai-v1-gateway-status-2026-04-23.md
  • Audience: 未来自己、接手运维的人、需要继续打磨这条 AI 网关的人
  • Status date: 2026-04-23

一句话结论

截至 2026-04-23,这条链路已经从“能用但不稳”推进到:

  • 正式公网入口已经切到 170.106.179.226:443
  • 这台 Windows 本机的 WLAN 网卡 DNS 已真改到公共解析源 8.8.8.8 / 1.1.1.1
  • Codex 现在直接走正式域名 https://key.tengokukk.com/openai/v1
  • 所有本地代理/代理环境变量都已撤掉
  • responses unary 已恢复正常
  • responses streaming 已恢复成一致的事件序列
  • chat/completions unary 已能在 tool_choice=required 下返回 tool_calls
  • 170 上 nginx 已补 streaming 友好参数

当前更准确的状态已经从“124 做边缘转发”推进到:

正式公网主链路:
外部域名 -> 170 nginx :443 -> 127.0.0.1:3301 -> 127.0.0.1:3000/openai-codex-oauth/v1
 
当前这台 Windows 机器上的 Codex 实际链路:
Codex -> https://key.tengokukk.com/openai/v1 -> 170 nginx -> 170:3301

当前真实状态

本机 Codex 当前配置

C:\Users\ASUS-KL\.codex\config.toml 当前有效关键配置:

model_provider = "crs"
model = "gpt-5.4"
 
[model_providers.crs]
base_url = "https://key.tengokukk.com/openai/v1"
wire_api = "responses"
requires_openai_auth = true

HKCU:\Environment 当前每用户代理环境变量:

HTTPS_PROXY=
HTTP_PROXY=
NO_PROXY=

C:\Users\ASUS-KL\.codex\auth.json 当前 key:

{
  "auth_mode": "apikey",
  "OPENAI_API_KEY": "sk-tengokukk-crs-20260422"
}

本机之前卡住的已确认根因

这次“你使用时卡住不动”的根因,已经在这台机器上确认清楚:

  • 之前这台机器的 WLAN 网卡 DNS 还是旧解析源
  • 所以 key.tengokukk.com 一直被解析到旧值 170.106.179.226
  • 这台机器到 170.106.179.226:443 的 TCP 直连失败
  • 同一台机器到旧边缘 124.220.233.126:443 的 TCP 直连成功
  • codex-tui.log 里实际出现的是 stream disconnected - retrying sampling request

所以,当时不是“服务器没修好”,而是:

本机网卡 DNS 指向旧解析源 -> 域名被解析到旧的 170 -> 而这台机器又直连不了 170 -> responses 采样流断开 -> 你看到卡住不动

本机最终收敛方案

现在这台机器已经不需要任何本地代理,最终状态是:

  • WLAN 网卡 DNS:8.8.8.8 / 1.1.1.1
  • C:\Users\ASUS-KL\.codex\config.toml:正式域名 https://key.tengokukk.com/openai/v1
  • HKCU:\Environment:不再保留 HTTP_PROXY / HTTPS_PROXY / NO_PROXY
  • 本地代理 127.0.0.1:4411127.0.0.1:4412 都不再是当前活跃链路

这个方案最终解决了:

  • 本机默认 DNS 旧值问题
  • 旧代理依赖问题
  • 本机到 170:443 的直连失败对正式域名使用的影响

170 服务器上的当前收敛结构

  • 公网域名:key.tengokukk.com
  • 正式公网入口:170.106.179.226:443
  • 当前公共 DNS 权威解析:170.106.179.226
  • nginx 站点:/etc/nginx/sites-available/key.tengokukk.com
  • 内层 AIClient2API:http://127.0.0.1:3301
  • 当前主 provider:openai-custom
  • 上游 codex oauth 网关:http://127.0.0.1:3000/openai-codex-oauth/v1

124 边缘机上的当前状态

  • 边缘机:124.220.233.126
  • nginx 站点:/etc/nginx/sites-available/key.tengokukk.com.conf
  • 证书:/etc/letsencrypt/live/key.tengokukk.com/
  • 当前角色:旧边缘/备用入口,不再是权威正式入口
  • 现存转发目标:http://170.106.179.226:3301/v1/
  • 现存根路径行为:/ -> 302 /openai/v1/models

170 nginx 当前关键配置

当前 170 的根路径与 /openai/ 都已具备正式入口所需行为:

location = / {
    return 302 /openai/v1/models;
}
 
location /openai/ {
    proxy_pass http://127.0.0.1:3301/;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Connection '';
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_cache off;
    proxy_read_timeout 3600;
    proxy_send_timeout 3600;
    chunked_transfer_encoding on;
    gzip off;
}

这次真正修掉了什么

1. 确认了问题不在 170 nginx,而在上游协议选型

直接实测 127.0.0.1:3000/openai-codex-oauth/v1 后确认:

  • /chat/completions 正常
  • /responses unary 返回 400 Bad Request
  • /responses streaming 也返回 error event

这意味着:

  • 让 3301 的主 provider 使用 openaiResponses-custom 是错误的收敛方向
  • 正确方向应该是:
    • 3301 对上游走 openai-custom / chat/completions
    • 对外继续同时兼容 responseschat/completions
    • responses 兼容交给 converter 与 fallback 处理

2. 把 3301 主 provider 切回 openai-custom

170 上 configs/config.json 已从:

"MODEL_PROVIDER": "openaiResponses-custom"

切到:

"MODEL_PROVIDER": "openai-custom"

原因:上游 3000 的健康路径是 chat/completions,不是 responses

3. 给 openai-custom unary 增加 stream fallback 聚合

修改文件:/srv/aiclient-2-api-mock/src/providers/openai/openai-core.js

新增能力:

  • 当 unary chat/completions 请求携带 tools
  • 且上游 direct unary 未返回 tool_calls
  • 自动改走 streaming 聚合
  • 最终重新收敛成标准 unary chat.completion

这一步解决了:

  • upstream streaming 有 tool_calls,但 unary 没有 tool_calls 的不一致
  • tool_choice=required 时原来只返回空 assistant 的问题

4. 修正 openai -> responses 的流式状态机

修改文件:/srv/aiclient-2-api-mock/src/converters/strategies/OpenAIConverter.js

修复点:

  • convertStreamChunk() 现在会把 requestId 传给 toOpenAIResponsesStreamChunk()
  • toOpenAIResponsesStreamChunk() 现在按单请求维护状态,不再每个 chunk 都当成新响应
  • response.created / response.in_progress / response.output_item.added 只在同一请求里初始化一次
  • 文本 delta 会稳定累加为同一个 msg_*
  • 完成时会输出一致的 response.output_text.done / response.completed

这一步解决了:

  • responses streaming 里重复出现多个 response.created
  • 文本被拆成多个无关 response id
  • unary fallback 里误继承 chat.completion.chunk 的对象类型

当前验证结果

已确认通过

2026-04-23 新增 Soxio 备用池节点

本次又新增了一组 OpenAI 兼容上游到 provider pool:

  • 上游基址:https://apikey.soxio.me/openai/v1
  • 目标模型:gpt-5.4
  • 加入池子位置:
    • openai-custom,节点名:soxio-openai-v1
    • openaiResponses-custom,节点名:soxio-responses-v1

这次不是只把配置写进文件,而是做了真实调用验证。

真实探测结果

直接对 Soxio 上游实测得到:

  • POST https://apikey.soxio.me/openai/v1/chat/completions
    • stream=true 时返回 200,可稳定输出流式 delta
    • stream=false 时返回 400,提示必须开启 streaming
  • POST https://apikey.soxio.me/openai/v1/responses
    • 也要求 stream=true

所以这组上游更适合作为:

  • responses / chat.completions 的流式执行节点
  • 尤其适合当前 Codex 这类 responses 流式采样链路

经 AIClient2API 转发后的真实验证

新增节点后,已经确认 AIClient2API 外层主池实际选中了:

  • soxio-openai-v1

日志里可见:

  • getServiceAdapter, provider: openai-custom ... (soxio-openai-v1)
  • Increasing usage count for openai-custom ... (soxio-openai-v1) after successful stream request

并且以下链路已经真实通过:

  1. http://127.0.0.1:3301/v1/responses

    • stream=true
    • 返回完整 response.created -> response.completed
    • 输出内容:INNER-SOXIO-OK
  2. http://127.0.0.1:3301/v1/chat/completions

    • stream=true
    • 正常返回 chat.completion.chunk
    • 输出内容:INNER-SOXIO-CHAT-OK
  3. https://key.tengokukk.com/openai/v1/responses

    • stream=true
    • 公网真实返回完整响应事件流
    • 输出内容:PUBLIC-SOXIO-OK

当前更准确的结论

截至这次变更后:

  • openai-codex-oauth 原来的账号限流问题仍然存在
  • openai-custom 池已经不再只有那一条坏上游
  • Soxio 节点已经能作为实际可工作的流式备用上游
  • 当前 responses 流式公网链路已经重新回到可用状态
  1. http://127.0.0.1:3301/v1/responses streaming

    • 返回一致的 response.created -> delta -> done -> completed
    • 文本可稳定拼成 STREAM-OK
  2. http://127.0.0.1:3301/v1/responses unary

    • 返回 200
    • 返回体内容为 UNARY-OK
  3. http://127.0.0.1:3301/v1/chat/completions unary + tool_choice=required

    • 返回 200
    • 返回 message.tool_calls
    • finish_reason = "tool_calls"
  4. https://127.0.0.1/openai/v1/responses + Host: key.tengokukk.com

    • 也就是 nginx loopback 闭环
    • 返回 200
    • 返回体内容为 GATEWAY-OK
  5. 124 边缘机上的 https://127.0.0.1/openai/v1/chat/completions + Host: key.tengokukk.com

    • 返回 200
    • 返回体内容为 SERVER124-LOOPBACK-CHAT-OK
  6. 124 边缘机上的 https://127.0.0.1/openai/v1/responses + Host: key.tengokukk.com

    • 返回 200
    • 返回体内容为 SERVER124-LOOPBACK-RESPONSES-OK
  7. 外部机器直接打 https://124.220.233.126/openai/v1/chat/completions + Host: key.tengokukk.com

    • 返回 200
    • 返回体内容为 EDGE-124-OK
  8. 外部机器直接打 https://124.220.233.126/openai/v1/chat/completionstool_choice=required

    • 返回 200
    • 返回 message.tool_calls
    • 参数里已携带 {\"command\":\"echo TOOL-EDGE-OK\"}
  9. 外部机器直接打 https://124.220.233.126/openai/v1/responses streaming

    • 返回稳定事件序列
    • 文本可稳定拼成 STREAM-EDGE-124-OK
  10. 公共 DNS 已切换到 124

  • tccli dnspod DescribeRecordList --Domain tengokukk.com
  • 8.8.8.8 查询结果都是 124.220.233.126
  1. 多个外部探测节点访问 https://key.tengokukk.com/
  • check-host.net 的西班牙 / 法国 / 印度 / 瑞典 / 乌克兰节点都返回 302
  • 解析到的实际目标 IP 都是 124.220.233.126
  1. 这台 Windows 本机上的正式域名 https://key.tengokukk.com/openai/v1/chat/completions
  • 在零代理下直接返回 DIRECT-DNS-NO-PROXY-OK
  1. 这台 Windows 本机上的 codex exec "Reply exactly CODEX-DIRECT-DNS-NO-PROXY-OK."
  • 在零代理下直接返回 CODEX-DIRECT-DNS-NO-PROXY-OK
  1. 这台 Windows 本机上的正式域名 codex exec 真实动作测试
  • 在零代理下直接成功
  • 已创建 C:\Users\ASUS-KL\.codex\.tmp\direct-domain-no-proxy-action-ok.txt
  • 文件内容为 DIRECT-DNS-NO-PROXY-ACTION-OK
  1. 这台 Windows 本机上的旧 proxy-env 方案
  • 在 DNS 真改好之前曾用于过渡
  • 现在已经不再需要
  1. 这台 Windows 本机上的旧 path proxy 4411 方案
  • 更早阶段用于过渡
  • 现在已经不再需要
  1. 这台 Windows 本机上的旧 path proxy 动作测试
  • 已实际调用 shell
  • 已创建 C:\Users\ASUS-KL\.codex\.tmp\local-hang-repro\action-ok.txt
  • 文件内容为 ACTION-OK

2026-04-23 补充:170 直连 443 为什么之前不通

这条后来已经查清并修掉了,真实根因不是 nginx、本机 DNS,也不是 Linux ufw/iptables

  1. 170.106.179.226 实际是 Tencent Lighthouse 实例,不是普通 CVM

    • 这就是为什么前面用 tccli cvm DescribeInstances 查不到
    • 实例真实 ID:lhins-nd7hu039
  2. 真正挡住公网 443 的层是 Lighthouse 防火墙

    • 修复前规则里只有 22 / 80 / 3000 / 3301 / ICMP
    • 没有 TCP 443
    • 所以外部连 170.106.179.226:443 会超时,而不是收到 nginx 响应
  3. 已执行的最小修复

    • 使用 tccli lighthouse CreateFirewallRules --region na-siliconvalley
    • lhins-nd7hu039 新增 0.0.0.0/0 -> TCP 443
    • 回读规则后 FirewallVersion 已从 3 变为 4
  4. 修复后的结果

    • 这台 Windows 本机 Test-NetConnection 170.106.179.226 -Port 443 现在已返回 TcpTestSucceeded=True
    • curl -k -I https://170.106.179.226 现在已直接返回 HTTP/1.1 200 OK
    • 所以“这台 Windows 本机直连不了 170:443”已经不再成立

当前仍需明确区分的现象

  1. 170 服务器访问“自己的公网域名/IP”可能卡住

    • 这更像云主机对自身公网地址的 hairpin/回环限制
    • 不等于 nginx 或 3301 本身坏了
    • 同一台机器使用 https://127.0.0.1 + Host: key.tengokukk.com 的 loopback 闭环是正常的
  2. 旧的 124 -> 170:3301 边缘链路仍然存在

    • 但它现在只是旧边缘/备用层,不再是权威正式入口
    • 当前正式域名 https://key.tengokukk.com/openai/v1 的权威解析已经切到 170.106.179.226

2026-04-23 补充:正式入口已从 124 切到 170

这一步后来也已经执行完成,当前“正式公网主入口仍然是 124”这条旧判断已经失效。

本次已完成的切换动作:

  1. 170 站点补齐正式入口行为

    • /etc/nginx/sites-available/key.tengokukk.com 新增:
      • location = / { return 302 /openai/v1/models; }
    • 所以 170 现在不只是能接 /openai/,根路径行为也和之前 124 的正式入口一致
  2. DNSPod 权威记录已改

    • key.tengokukk.comA 记录 RecordId=2280257289
    • 已从 124.220.233.126 改到 170.106.179.226
  3. 外部非本机实测证据

    • 124.220.233.126 这台外部机器上:
      • getent ahosts key.tengokukk.com 已返回 170.106.179.226
      • curl -k -I https://key.tengokukk.comREMOTE_IP 已是 170.106.179.226
      • curl -k https://key.tengokukk.com/openai/v1/chat/completions 带真实 key 的返回体内容为 CUTOVER-REMOTE-124-OK
    • 这说明现在不是“只有当前 Windows 本机能通”,而是外部非本机也已经通过正式域名命中 170
  4. DNS 传播说明

    • 8.8.8.8 / 1.1.1.1 / 223.5.5.5 现在都已经解析到 170.106.179.226
    • 如果某台机器短时间仍看到 124,优先判断为该机器自己的旧缓存尚未过期,不再是权威记录未切换

2026-04-23 补充:本地 127.0.0.1:4411/openai/v1/responses413 已修掉

这条后来也单独修过,根因是两层叠加:

  1. 本地 4411 代理仍然硬编码指向旧边缘 124.220.233.126

    • 文件:C:\\Users\\ASUS-KL\\.codex\\.tmp\\local-key-proxy\\key-edge-proxy.mjs
    • 同目录下的 key-connect-proxy.mjs 也把 key.tengokukk.com 固定映射到 124
  2. 124170 两层 nginx 都没有显式放大请求体上限

    • 默认会命中 nginx 的请求体限制
    • 在大一点的 responses 请求上返回 413 Payload Too Large

已执行的修复:

  • 把本地 4411/4412 旧代理都改为指向 170.106.179.226
  • 170 站点 /etc/nginx/sites-available/key.tengokukk.com 增加 client_max_body_size 50m;
  • 124 站点 /etc/nginx/sites-available/key.tengokukk.com.conf 增加 client_max_body_size 50m;
  • 已重载两台机器的 nginx,并重启本地 4411 代理

修复后的验证结论:

  • 同一份约 1.2MBresponses 请求体,再打 4411 已不再返回 413
  • 同一份约 1.2MB 的请求体,打 124 也不再返回 413
  • 修复后返回的是后端 500,说明请求已经穿过请求体限制层,413 这层问题已解除
  • 也就是说,这次修掉的是“请求在 nginx/body-size 层被拦住”,不是顺手重做 responses 上游语义

建议如何理解这条链路

不要再把它理解成“responses 上游已经完全健康”。

更准确的理解是:

上游真实健康面:chat/completions
3301 对外兼容面:responses + chat/completions
responses 的稳定性来自 converter + stream fallback
不是来自上游原生 /responses 健康

证据文件

本次文档对应的一次性验证输出已落到:

  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-gateway-verification.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-default-nslookup.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-google-nslookup.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-remote-checks.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-public-chat.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-local-codex-proxy-validation.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-global-edge-cutback-to-124.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-direct-domain-proxyenv-cutover.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-key-tengokukk-final-direct-dns-cutover.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-170-lighthouse-443-fix.txt
  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-local-4411-413-fix.txt

下一步最自然的工作

如果继续往“工业级”推进,优先级建议是:

  1. 给 openai/custom unary fallback 加更明确的日志标记

    • 区分 direct unary 成功
    • direct unary 缺 tool_call 后自动回退 stream
    • unary final object 已重建
  2. 视需要把这组补丁回写到真正受控的 repo/工作副本

    • 当前修改已经在 170 运行面生效
    • 但如果要长期维护,最好同步到正式代码仓库而不是只留在线上机器
  3. 再决定是否要让 170:443 承担正式公网入口

    • 现在它已经可以直连
    • 但当前生产稳定链路已经收敛到 124 -> 170:3301
    • 如果要切主入口,应单独评估证书、DNS、回滚和外部验证

2026-04-23 补充:第二把 Soxio key 已加入池子

本次又把同一组 Soxio 上游的第二把 key 加进了 provider pool,不再只依赖单节点:

  • openaiResponses-custom
    • soxio-responses-v1
    • soxio-responses-v1-b
  • openai-custom
    • soxio-openai-v1
    • soxio-openai-v1-b

第二把 key 对应值为:

cr_75927920e39d477d32474e98c1228ee90731fb846cce8cd8f87cac954ca6a656

这次不是只把 key 写进去,而是确认了它已经真实被初始化并参与选路:

  • configs/provider_pools.json 中可见:
    • customName: "soxio-responses-v1-b"
    • customName: "soxio-openai-v1-b"
  • logs/app-2026-04-23.log 中可见:
    • Initialized node: soxio-openai-v1-b
    • getServiceAdapter ... (soxio-openai-v1-b)

2026-04-23 补充:Soxio 的“流式上游”已被外层补成稳定 unary

这一步的目标不是让 Soxio 自己学会 unary,而是让外面看起来已经能稳定 unary。

先确认到的上游事实:

  • https://apikey.soxio.me/openai/v1/chat/completions
    • stream=true 正常
    • stream=false 会被上游拒绝
  • https://apikey.soxio.me/openai/v1/responses
    • 实际也要求 stream=true

所以这次真正落地的不是“换一个更听话的上游”,而是:

  • 170:/srv/aiclient-2-api-mock/src/providers/openai/openai-core.js
  • 让 unary 请求先按正常 unary 发
  • 如果上游明确报出这是 stream-only
  • 就自动回退到 _collectUnaryFromStream(...)
  • 再把收集到的流式结果重新收敛成外部看到的 unary 响应

本次确认存在的关键代码与日志信号:

  • 代码命中:
    • _shouldFallbackToStreamOnUnaryError
    • _collectUnaryFromStream
  • 日志命中:
    • Unary request rejected by upstream as stream-only. Falling back to stream aggregation.

这意味着现在的真实行为已经变成:

外层 unary 请求
-> 先试 direct unary
-> 如果 Soxio 拒绝 unary
-> 自动改走 stream
-> 再由 AIClient2API 聚合成 unary 返回

2026-04-23 补充:这轮的最终实测结果

这轮不是只看配置和日志,而是重新做了真实调用:

  1. 内层 unary chat

    • 目标:http://127.0.0.1:3301/v1/chat/completions
    • 返回:HTTP 200
    • 内容:INNER-UNARY-CHAT-OK
  2. 公网 unary responses

    • 目标:https://key.tengokukk.com/openai/v1/responses
    • 返回:HTTP 200
    • 输出:PUBLIC-UNARY-RESPONSES-OK
  3. 运行日志

    • 已出现 stream-only -> unary fallback 的日志
    • 已看到 soxio-openai-v1soxio-openai-v1-b 两个节点都被初始化和命中

所以截至这一步,关于 Soxio 这条上游,更准确的结论应该写成:

Soxio 本身仍然偏 streaming-first
但 AIClient2API 外层现在已经把它补成:
- streaming 可用
- unary 也可用
- 公网看起来是稳定 unary

本轮新增证据文件

本轮新增的原始命令与返回结果已落到:

  • E:\My Project\Atramenti-Console\codex\plugins\obsidian\data\docs\codex-knowledge\_artifacts\2026-04-23-soxio-second-key-and-unary-aggregation.txt