核心主旨:聚合 ChatGPT、Claude 等官方 OAuth 与 DeepSeek 等第三方 API,经 nginx 反代分发的完整部署流程
- 本篇深度梳理了在 Agent 场景下的实战踩坑与加固细节。
- 提炼自生产环境部署经验:兼顾轻量低耗与高安全性,避免冗余依赖。
- 涵盖关键配置代码片段、数据链路排障要点与系统级自愈方案。
同时用几个 AI 上游很麻烦:每个都要单独配 key、单独改客户端,额度也各管各的。用 CLIProxyAPI 在服务器上把它们聚合成一个端点,对外只给一把 key,客户端改个 base_url 就能用,/model 随时切模型。下面是完整部署流程,新服务器按顺序执行即可。
适用场景
- 多上游自用:官方 OAuth 与第三方 API 共用一个
base_url,/model切模型不用改配置;服务器在境外且国内可直连(本文是日本节点)时,客户端也不必自己再挂代理 - 对外分发:账号额度用不完(比如 GPT Pro 20x),装到服务器上就能公网分发——本机版只能服务自己或局域网,一把 key 给团队 / 朋友,不用再搭 VPN
- 多客户端复用:Codex、Claude Code、Gemini CLI、Cursor 等共用同一把 key,新增或替换上游时客户端不动
一、准备
| 项 | 说明 |
|---|---|
| 服务器 | 能跑 nginx 的 Linux(本文 Ubuntu 24.04),CPA 常驻内存约 57MB |
| 域名 + 证书 | 反代必须有 HTTPS;没有就用 certbot --nginx -d 你的域名 申请 |
| nginx | 反代与鉴权都在这一层 |
| 上游账号(可选) | ChatGPT / Claude / xAI / Kimi 等任一,用于 OAuth 登录 |
| 第三方 Key(可选) | DeepSeek 等 OpenAI 兼容服务,官方额度用完后接管 |
版本:CPA v7.3.4、codex-cli 0.154.0。
二、安装 CPA
cd /tmp
curl -fsSL -o cpa.tar.gz \
https://github.com/router-for-me/CLIProxyAPI/releases/download/v7.3.4/CLIProxyAPI_7.3.4_linux_amd64.tar.gz
tar xzf cpa.tar.gz
mkdir -p ~/cliproxyapi
install -m 0755 cli-proxy-api ~/cliproxyapi/cli-proxy-api
单文件 Go 程序,约 64MB。用 systemd 托管:
# /etc/systemd/system/cli-proxy-api.service
[Unit]
Description=CLIProxyAPI - unified upstream gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=azureuser # 改成你的运行用户
WorkingDirectory=/home/azureuser/cliproxyapi
ExecStart=/home/azureuser/cliproxyapi/cli-proxy-api -config /home/azureuser/.cli-proxy-api/config.yaml
Restart=on-failure
RestartSec=3
MemoryMax=384M
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now cli-proxy-api
三、写配置
~/.cli-proxy-api/config.yaml:
# 只监听本机:公网必须先过 nginx
host: "127.0.0.1"
port: 8317
remote-management:
allow-remote: true # 反代场景建议 true
secret-key: "管理密钥" # 明文填,启动时自动 bcrypt 加密回写
auth-dir: "/home/azureuser/.cli-proxy-api" # OAuth 凭证目录
api-keys: # 客户端访问 CPA 用的密钥
- "sk-cpa-xxxxxxxx"
debug: false
三个关键点:
host绑127.0.0.1,公网只能从 nginx 进secret-key管管理接口,api-keys管客户端调用,两者别混- 上游 provider 全部在管理面板里配,配置文件保持干净
四、登录上游账号
CPA 内置多种 OAuth 登录,按需挑:
| 上游 | 命令 |
|---|---|
| ChatGPT / Codex | -codex-device-login(服务器)、-codex-login(本机浏览器) |
| Claude | -claude-login |
| xAI | -xai-login |
| Kimi | -kimi-login |
| Meta | -meta-login |
| Devin | -devin-login |
| Antigravity | -antigravity-login |
| Google Vertex | -vertex-import 服务账号.json |
以无浏览器的服务器为例,用设备码登录 Codex:
./cli-proxy-api -config ~/.cli-proxy-api/config.yaml -codex-device-login
# Codex device URL: https://auth.openai.com/codex/device
# Codex device code: XXXX-XXXX
打开网址输码授权,凭证落到 auth-dir。
当然也可以直接在 Web 面板里点「认证文件 → 对应上游 → 发起登录」。OAuth 回调端口被占用时用 -oauth-callback-port 指定,无浏览器加 -no-browser。
⚠️ 不要照搬教程里的
forced_login_method = "api"/preferred_auth_method = "apikey":已有 ChatGPT 登录态时,Codex 会判定「要用 API key 登录」,登出并删掉auth.json。加 provider 只靠env_key。
五、nginx 反代分发(核心)
CPA 只监听本机,对外必须经 nginx。策略:隐藏路径 + Basic Auth + 限速,三条路径分开管面板页、管理 API、客户端 API。
1. 建账号密码
sudo htpasswd -c /etc/nginx/.htpasswd-cpa cpadmin # 没有 htpasswd 就先装 apache2-utils
2. 写反代片段
# /etc/nginx/snippets/cpa.conf(用 include 引入 server 块)
# 限速区(放 http 块;已定义过就跳过)
limit_req_zone $binary_remote_addr zone=admin_zone:10m rate=10r/m;
location = /cpa-adm-XXXXXXXX { return 301 /cpa-adm-XXXXXXXX/management.html; }
location = /cpa-adm-XXXXXXXX/ { return 301 /cpa-adm-XXXXXXXX/management.html; }
# ① 面板静态页:Basic Auth + 限速
location ^~ /cpa-adm-XXXXXXXX/ {
auth_basic "CPA Admin";
auth_basic_user_file /etc/nginx/.htpasswd-cpa;
limit_req zone=admin_zone burst=60 nodelay;
proxy_pass http://127.0.0.1:8317/;
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_buffering off; # SSE / 流式必需
proxy_read_timeout 3600s; # 长任务别被 60s 掐断
client_max_body_size 200m;
}
# ② 管理 API:面板默认就调这里,鉴权交给 CPA
location ^~ /v0/ {
proxy_pass http://127.0.0.1:8317/v0/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
}
# ③ 客户端 API:隐藏路径 + api-key
location ^~ /cpa-api-XXXXXXXX/ {
proxy_pass http://127.0.0.1:8317/;
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_buffering off;
proxy_read_timeout 3600s;
client_max_body_size 200m;
}
XXXXXXXX 换成自己的随机串(路径本身就是一层防护)。没有现成 server 块的话,最小骨架:
server {
listen 443 ssl;
server_name 你的域名;
ssl_certificate /etc/letsencrypt/live/你的域名/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/你的域名/privkey.pem;
include /etc/nginx/snippets/cpa.conf;
}
3. 为什么要拆路径
nginx 的 auth_basic 用 Authorization: Basic ... 认证,而 CPA 面板用 Authorization: Bearer <管理密钥> 调 API(management.html 里写死了 Bearer ${managementKey})。两者共用同一个头:Bearer 会顶掉 Basic,auth_basic 直接 401;用变量喂空值也不会关闭认证(实测返回 realm="" 的 401)。
所以面板页归 Basic Auth,管理 API 走一条不带 auth_basic 的路径,由 CPA 自己校验密钥;客户端 API 再走一条隐藏路径:
| 路径 | 用途 | 鉴权 |
|---|---|---|
/cpa-adm-XXXXXXXX/ | 面板静态页 | Basic Auth |
/v0/ | 管理 API(面板默认调用) | CPA 管理密钥(Bearer) |
/cpa-api-XXXXXXXX/v1/ | 客户端 API | CPA api-key(Bearer) |
4. 面板默认服务地址不带路径
面板取的是 window.location 里不带路径的协议 + 域名 + 端口:
$f = () => {
const { protocol, hostname, port } = window.location;
return Zf(`${protocol}//${hostname}${port ? `:${port}` : ""}`);
};
所以请求会打到 https://域名/v0/management/...(根路径),而不是 /cpa-mgmt-.../ 下的那条。这样配会 404,nginx 日志里能看到 /v0/management/config 没有路由。
两个解法:面板里手动把服务地址填全,或在 nginx 补一条根路径 /v0/ 路由。上面片段用的是后者。
改完检查并重载:
sudo nginx -t && sudo systemctl reload nginx
六、接入第三方 API(以 DeepSeek 为例)
登录面板(https://域名/cpa-adm-XXXXXXXX/management.html)后,在「提供商」里加一条 OpenAI 兼容:
| 字段 | 值 |
|---|---|
| 名称 | deepseek |
| base-url | https://api.deepseek.com |
| api-key | DeepSeek 的 sk-... |
| 模型 | deepseek-flash(要更大就再加 deepseek-v4-pro) |
base-url带不带/v1都行;alias留空会用name当模型名。
任何 OpenAI 兼容服务同理:填 base-url + api-key 即可,官方 OAuth 与这些第三方模型会一起出现在 /v1/models 里。保存后面板会把配置写回 config.yaml 并热重载,无需重启。
七、验证
三种协议各测一遍(走公网入口):
BASE=https://域名/cpa-api-XXXXXXXX/v1
KEY=sk-cpa-xxxxxxxx
# 1) 模型列表(官方 OAuth 与第三方模型的合集)
curl -s "$BASE/models" -H "Authorization: Bearer $KEY"
# 2) OpenAI 协议
curl -s "$BASE/chat/completions" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-flash","messages":[{"role":"user","content":"回复:A-OK"}]}'
# → A-OK
# 3) Responses 协议(Codex 用的就是它)
curl -s "$BASE/responses" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-flash","input":"回复:R-OK"}'
鉴权矩阵(都应满足):
面板页 无认证 → 401
面板页 Basic → 200
管理API 正确 Bearer → 200
管理API 错误/无 密钥 → 401
分发API 正确 key → 200
分发API 无 key → 401
八、客户端接入
Codex 指向 CPA(~/.codex/config.toml):
model_provider = "cpa"
model = "gpt-5.6-sol"
[model_providers.cpa]
name = "CPA"
base_url = "http://127.0.0.1:8317/v1"
experimental_bearer_token = "sk-cpa-xxxxxxxx"
wire_api = "responses"
supports_websockets = true
/model 里会同时出现官方 OAuth 的模型和第三方模型,额度用光时切过去,会话不断。
分发给其他客户端(同一把 key):
# OpenAI 兼容
OPENAI_BASE_URL = https://域名/cpa-api-XXXXXXXX/v1
OPENAI_API_KEY = sk-cpa-xxxxxxxx
# Claude Code
export ANTHROPIC_BASE_URL="https://域名/cpa-api-XXXXXXXX"
export ANTHROPIC_AUTH_TOKEN="sk-cpa-xxxxxxxx"
九、安全与分发建议
- CPA 只绑
127.0.0.1,公网必须过 nginx(HTTPS) - 面板页 Basic Auth + 管理密钥双因素;管理 API 连续 5 次失败封禁约 30 分钟
- 客户端 API 只靠 api-key,可随时增删(泄露一个删一个)
- 隐藏路径 + 限速,降低被扫概率
风险:分发出去的官方模型请求烧的是自己账号的额度,给的人越多越可能封号。分发给不熟的人,建议只发第三方付费模型(按量计费)或加 IP 白名单。
附录:为什么需要这层网关
/model 弹出的是当前 provider 的模型目录,切的是模型 slug,不是 provider。翻 Codex 源码可确认:ModelPreset 没有 provider 字段。
pub struct ModelPreset {
pub id: String,
pub model: String, // 只有模型 slug
pub display_name: String,
// ... 没有 provider
}
会话里 provider 固定,想在多个上游之间切只有两条路:退出后用不同 --profile 重开,或把上游合成一个 provider——后者就是第 2–6 节做的事。
小结
- 部署顺序:装 CPA → 写配置 → 登录上游 → nginx 反代 → 加第三方 API → 验证
- 登录方式按上游选:Codex 用设备码,Claude/xAI/Kimi 等用对应
-xxx-login,Vertex 导入服务账号 - 反代必须拆路径:面板页走 Basic Auth,管理/客户端 API 走 Bearer
- 面板默认服务地址不带路径,记得补
/v0/路由 - 网关让客户端只配一个
base_url就能跨上游切换;对外分发的额度风险要提前评估
文章标题:用 CLIProxyAPI 在服务器搭多上游统一网关
文章链接:https://20.48.50.55.sslip.io/dev/posts/2026-09-17-codex-cpa-gateway/
许可协议:本站原创内容采用 CC BY-NC-SA 4.0 国际许可协议,转载请注明作者出处与原文链接。
长按或连续点击「注入能量」,为当前节点充入赛博算力!