Agent VERIFIED POST

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

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

BING BING
约 7 分钟阅读
3307 字
🤖 BING-AI // 核心速览 (TL;DR)

核心主旨:聚合 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/客户端 APICPA 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-urlhttps://api.deepseek.com
api-keyDeepSeek 的 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 就能跨上游切换;对外分发的额度风险要提前评估
🏷️ 标签:
⚡ CYBER POWER CELL // 能量补给站
已注入能量: 42 瓦时

长按或连续点击「注入能量」,为当前节点充入赛博算力!

28%