用CLIProxyAPI把ChatGPT订阅接入Codex和第三方客户端:原理、部署与风险

7月19日,我在一台美国云服务器上部署了CLIProxyAPI(下文简称CPA),用ChatGPT/Codex OAuth登录自己的订阅账号,再向外提供OpenAI兼容接口。部署完成后,Codex CLI、Cursor以及普通OpenAI SDK都可以通过同一个HTTPS地址调用。

这篇文章记录完整过程。重点回答两个问题:它到底做了什么,以及怎样从一台空服务器搭到真正能调用模型。

CLIProxyAPI请求链路架构图

先说边界:这不是OpenAI官方API,也不是购买ChatGPT订阅后自动获得的API额度。它是第三方项目对Codex OAuth能力做的协议适配。个人实验可以研究,生产系统应优先使用OpenAI Platform API。文末会单独讲账号风险。

一、原理是什么?

1. ChatGPT订阅、Codex OAuth和官方API不是一回事

三者最容易混淆:

名称 认证方式 面向场景 计费/额度
ChatGPT网页和客户端 ChatGPT账号 人工对话和产品功能 订阅套餐
Codex CLI/IDE ChatGPT OAuth或API Key 编程Agent 可使用套餐中的Codex权益
OpenAI Platform API Platform API Key 程序化调用 独立按量计费

CPA走的是Codex OAuth路线。它不会把ChatGPT密码保存在配置文件里,而是让用户打开OpenAI官方授权页。授权成功后,CPA保存access token和refresh token,用它们访问Codex上游。

2. CPA做了两次转换

客户端看到的是熟悉的OpenAI接口:

1
2
3
GET  /v1/models
POST /v1/chat/completions
POST /v1/responses

CPA在中间负责:

  1. 校验客户端发送的CPA API Key。
  2. 把OpenAI兼容请求转换成Codex上游能够理解的请求。
  3. 使用本地保存的OAuth凭据访问上游。
  4. 把响应重新转换成OpenAI兼容JSON或SSE流。

完整链路如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Cursor / Codex CLI / OpenAI SDK

│ HTTPS + CPA API Key

Nginx(公网443端口)


CLIProxyAPI(127.0.0.1:8317)

│ Codex OAuth Token

OpenAI Codex上游


模型响应、工具调用、SSE事件

这里有三套不同的凭据,不要混用:

凭据 用途
CPA API Key Cursor、SDK、Codex CLI调用/v1/*
Management Key 登录CPA管理面板和调用管理API
Codex OAuth凭据 CPA访问OpenAI上游,保存在auths/目录

3. 为什么还要Nginx?

CPA本身监听8317端口,但我没有把它直接暴露到公网,而是只绑定宿主机回环地址:

1
127.0.0.1:8317

公网只开放Nginx的443端口。Nginx负责HTTPS证书、HTTP跳转、流式转发,同时阻断管理页面。这样做至少避免了三件事:

  • CPA明文HTTP直接暴露;
  • 管理接口被公网扫描;
  • OAuth回调端口暴露给整个互联网。

二、部署前准备

这次使用的环境是:

1
2
3
4
5
Ubuntu 18.04
Docker 20.10
Docker Compose 1.29
Nginx
域名已解析到服务器公网IP

服务器配置很低,只有1核、约481MB内存。CPA空闲时占用约37MB内存,可以运行,但我仍建议至少准备1GB内存。

域名先添加A记录:

1
cpa.example.com → 你的服务器公网IP

确认解析:

1
getent ahostsv4 cpa.example.com

云安全组只需开放:

1
2
3
22/tcp   SSH
80/tcp HTTP和证书签发
443/tcp HTTPS API

8317和OAuth回调端口1455不应直接开放公网。

三、用Docker Compose部署CLIProxyAPI

官方项目:

1
https://github.com/router-for-me/CLIProxyAPI

管理面板:

1
https://github.com/router-for-me/CLIProxyAPI-WebUI

1. 创建目录

1
2
3
mkdir -p /opt/cli-proxy-api/{auths,logs}
cd /opt/cli-proxy-api
chmod 700 auths

生成两套独立密钥:

1
2
openssl rand -hex 32   # CPA API Key
openssl rand -hex 32 # Management Key

不要把真实密钥贴到博客、Git仓库或Docker镜像中。

2. 创建config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
host: "0.0.0.0"
port: 8317

auth-dir: "/root/.cli-proxy-api"

api-keys:
- "替换为CPA_API_KEY"

debug: false
logging-to-file: true
usage-statistics-enabled: true

remote-management:
allow-remote: false
secret-key: "替换为MANAGEMENT_KEY"
disable-control-panel: false
panel-repo: "https://github.com/router-for-me/CLIProxyAPI-WebUI"

设置权限:

1
chmod 600 /opt/cli-proxy-api/config.yaml

allow-remote: false表示管理API只接受本地来源。但反向代理可能让后端看到的来源变成127.0.0.1,因此不能只靠这一项保护公网管理接口,Nginx还要明确阻断管理路径。

3. 创建docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: "3.8"

services:
cli-proxy-api:
image: eceasy/cli-proxy-api:latest
container_name: cli-proxy-api
restart: unless-stopped

ports:
- "127.0.0.1:8317:8317"
- "127.0.0.1:1455:1455"

volumes:
- ./config.yaml:/CLIProxyAPI/config.yaml
- ./auths:/root/.cli-proxy-api
- ./logs:/CLIProxyAPI/logs

启动:

1
2
3
4
cd /opt/cli-proxy-api
docker-compose pull
docker-compose up -d
docker logs cli-proxy-api --tail 100

正常日志应包含:

1
API server started successfully on: 0.0.0.0:8317

4. 老Docker为什么可能报pthread_create failed?

我在这台Ubuntu 18.04服务器上遇到过:

1
runtime/cgo: pthread_create failed: Operation not permitted

这不是内存耗尽,而是旧Docker默认seccomp规则和新版本Go运行时之间的兼容问题。确认根因后,我在服务中增加:

1
2
security_opt:
- seccomp=unconfined

完整位置:

1
2
3
4
5
services:
cli-proxy-api:
image: eceasy/cli-proxy-api:latest
security_opt:
- seccomp=unconfined

重新创建容器:

1
docker-compose up -d --force-recreate

这是兼容旧环境的退让,会降低容器的系统调用隔离能力。更好的长期方案是升级操作系统和Docker,而不是永久关闭seccomp。

四、完成ChatGPT/Codex OAuth登录

1. 在服务器启动登录流程

1
2
3
4
cd /opt/cli-proxy-api

docker-compose exec cli-proxy-api \
/CLIProxyAPI/CLIProxyAPI --codex-login --no-browser

终端会输出一条OpenAI官方授权链接,并等待回调。

2. 为什么浏览器最后会访问localhost?

授权链接中的回调地址通常是:

1
http://localhost:1455/auth/callback

这里的localhost指打开浏览器的那台电脑,不是云服务器。因此远程登录有两种做法。

第一种是SSH端口转发。在自己的电脑运行:

1
ssh -L 1455:127.0.0.1:1455 root@服务器IP

保持SSH连接,然后在同一台电脑的浏览器中打开授权链接。浏览器访问localhost:1455时,SSH会把回调转发到服务器。

第二种是手工回填。浏览器完成OpenAI登录后,即使最后显示:

1
ERR_CONNECTION_REFUSED

也不代表授权失败。复制地址栏中的完整回调URL:

1
http://localhost:1455/auth/callback?code=...&state=...

粘贴回等待中的CPA命令即可。回调URL包含一次性授权码,不要发到群聊、论坛或工单里。

成功后会看到:

1
2
Codex authentication successful
Authentication saved to /root/.cli-proxy-api/codex-xxx.json

宿主机对应文件位于:

1
/opt/cli-proxy-api/auths/

这类JSON包含刷新令牌,敏感程度和登录凭据相当。

五、配置Nginx和HTTPS

先安装:

1
2
apt-get update
apt-get install -y nginx certbot python3-certbot-nginx

创建Nginx站点配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server {
listen 80;
listen [::]:80;
server_name cpa.example.com;

location = /management.html {
return 404;
}

location ^~ /v0/management {
return 404;
}

location / {
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;
proxy_request_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}

启用并检查:

1
2
3
4
5
ln -s /etc/nginx/sites-available/cpa.example.com \
/etc/nginx/sites-enabled/cpa.example.com

nginx -t
systemctl reload nginx

申请证书:

1
2
3
4
certbot --nginx \
-d cpa.example.com \
--agree-tos \
--redirect

验证:

1
2
curl -I http://cpa.example.com/v1/models
curl -I https://cpa.example.com/v1/models

HTTP应跳转到HTTPS;没有API Key的模型请求应返回401,而不是200。

六、管理面板怎么访问?

我没有把管理面板开放到公网。需要管理时,从自己的电脑建立隧道:

1
ssh -L 8317:127.0.0.1:8317 root@服务器IP

浏览器打开:

1
http://127.0.0.1:8317/management.html

登录时填写remote-management.secret-key,不是给客户端使用的CPA API Key。

公网应验证为404:

1
2
curl -I https://cpa.example.com/management.html
curl -I https://cpa.example.com/v0/management/config

七、怎样确认接口真的能用?

只看到容器Up还不够。至少要测鉴权、非流式、流式和Responses API。

1. 模型列表

1
2
curl https://cpa.example.com/v1/models \
-H "Authorization: Bearer 你的CPA_API_KEY"

2. Chat Completions

1
2
3
4
5
6
7
8
9
10
curl https://cpa.example.com/v1/chat/completions \
-H "Authorization: Bearer 你的CPA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4-mini",
"messages": [
{"role": "user", "content": "请只回复:接口正常"}
],
"stream": false
}'

3. SSE流式输出

1
2
3
4
5
6
7
8
9
10
curl -N https://cpa.example.com/v1/chat/completions \
-H "Authorization: Bearer 你的CPA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4-mini",
"messages": [
{"role": "user", "content": "解释Go的GMP调度"}
],
"stream": true
}'

结尾应收到:

1
data: [DONE]

4. Responses API

1
2
3
4
5
6
7
8
curl https://cpa.example.com/v1/responses \
-H "Authorization: Bearer 你的CPA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4-mini",
"input": "Reply exactly: RESPONSES_OK",
"stream": false
}'

我实际验证过的结果包括:

接口 状态
带Key调用/v1/models HTTP 200
不带Key调用/v1/models HTTP 401
Chat Completions非流式 HTTP 200
Chat Completions流式 HTTP 200,并收到[DONE]
Responses非流式 HTTP 200
Responses流式 HTTP 200,并收到response.completed

模型回答成功才算端到端可用。只验证/models,不能证明OAuth上游和推理链路正常。

八、Codex CLI如何接入?

Codex配置文件:

1
~/.codex/config.toml

配置一个自定义Provider:

1
2
3
4
5
6
7
8
9
model = "gpt-5.4-mini"
model_provider = "my_cpa"

[model_providers.my_cpa]
name = "My CPA"
base_url = "https://cpa.example.com/v1"
env_key = "MY_CPA_API_KEY"
wire_api = "responses"
requires_openai_auth = false

设置环境变量:

1
export MY_CPA_API_KEY="你的CPA_API_KEY"

然后启动:

1
codex

wire_api = "responses"不能随便改成chat。当前Codex Agent围绕Responses API、流式事件和工具调用工作。普通文字对话成功,只能证明基础请求通了;还应再测试一次真实文件操作:

1
创建hello.txt,写入CPA_CODEX_OK,然后重新读取并确认内容。

文件真实落盘,才证明工具调用、多轮回传和Agent循环也兼容。

九、Cursor怎么配置?

进入:

1
Cursor Settings → Models → API Keys

配置:

1
2
3
OpenAI API Key:CPA API Key
Override OpenAI Base URL:开启
Base URL:https://cpa.example.com/v1

然后手工添加CPA返回的模型ID,例如:

1
2
3
gpt-5.4-mini
gpt-5.4
gpt-5.6-sol

验证时不要选择Auto,要明确选择自定义模型,并在服务器上观察:

1
2
tail -f /var/log/nginx/access.log
docker logs -f cli-proxy-api

Cursor的Tab补全使用它自己的专用模型,不走自定义OpenAI API。Chat通常可以使用;Agent还取决于模型和代理对toolstool_calls、工具结果回传的兼容程度。

十、常用维护命令

查看服务:

1
2
3
cd /opt/cli-proxy-api
docker-compose ps
docker logs cli-proxy-api --tail 100

更新:

1
2
3
cd /opt/cli-proxy-api
docker-compose pull
docker-compose up -d

备份配置和OAuth凭据:

1
2
3
4
5
tar -C /opt -czf "/root/cpa-backup-$(date +%F).tar.gz" \
cli-proxy-api/config.yaml \
cli-proxy-api/auths

chmod 600 /root/cpa-backup-*.tar.gz

备份文件含有API Key、管理密钥和OAuth Token,最好再做加密,不要上传普通网盘。

十一、这种方式会不会封号?

有风险,个人使用也不能保证安全。

OpenAI明确支持的是官方Codex客户端使用ChatGPT登录,以及Platform API Key调用官方API。把Codex OAuth订阅能力转换为通用OpenAI兼容API,并没有得到OpenAI官方明确授权。可能的处理包括OAuth吊销、重新登录、限流、功能限制,严重时也可能暂停账号。

风险会在以下情况下明显增加:

  • 把API Key交给其他人;
  • 对外售卖或嵌入公开产品;
  • 多账号轮换;
  • 高并发、全天批处理;
  • 上游限流后无限重试;
  • 尝试绕过套餐、地区或安全限制。

我只将它作为个人实验环境,并保持单账号、低并发。重要账号和生产业务不应依赖这种未获官方保证的链路。

十二、最后回看这套架构

这次部署真正容易踩坑的地方,不是Docker命令,而是四个边界:

  1. ChatGPT订阅不等于Platform API额度。
  2. OAuth回调里的localhost属于浏览器所在电脑。
  3. 管理面板不能仅靠allow-remote: false保护,Nginx也要阻断。
  4. 容器启动和/models成功都不代表推理可用,必须实际调用模型并测试流式事件。

CPA把不同客户端统一到了OpenAI接口格式,这一点确实方便。代价也很明确:OAuth凭据进入第三方程序,账号合规风险由使用者承担,协议兼容性还要靠真实Agent任务验证。

如果只是使用Codex,最稳妥的方式仍然是官方Codex CLI直接登录ChatGPT;如果需要通用程序API,最稳妥的是OpenAI Platform API Key。CPA更适合研究协议、个人实验和验证客户端兼容性,不应被误认为官方提供的订阅转API方案。

参考资料