用 CLIProxyAPI 在服务器搭多上游统一网关

聚合 ChatGPT、Claude 等官方 OAuth 与 DeepSeek 等第三方 API,经 nginx 反代分发的完整部署流程

同时用几个 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 节做的事。

小结

  1. 部署顺序:装 CPA → 写配置 → 登录上游 → nginx 反代 → 加第三方 API → 验证
  2. 登录方式按上游选:Codex 用设备码,Claude/xAI/Kimi 等用对应 -xxx-login,Vertex 导入服务账号
  3. 反代必须拆路径:面板页走 Basic Auth,管理/客户端 API 走 Bearer
  4. 面板默认服务地址不带路径,记得补 /v0/ 路由
  5. 网关让客户端只配一个 base_url 就能跨上游切换;对外分发的额度风险要提前评估

版权说明

本文由 BING 撰写,采用 CC BY-NC-SA 4.0 许可协议。转载请注明作者与原文链接。

https://xbzhang.xyz/dev/posts/2026-09-17-codex-cpa-gateway/

搜索文章

输入关键词查找,使用 ↑ ↓ 选择、Enter 打开

从标题、摘要、分类和标签中查找。

BINGBLOG · AI

AI 助读

回答由模型生成,请对重要信息自行核实。

你好,我可以根据本站文章帮助查找信息,也可以回答关于本站技术实践的问题。

OWNER ACCESS

博主验证

输入认证器中的 6 位动态码,以解除公共限速并启用模型选择。