前言

之前 在本地部署了CPA。本质上,本地部署和云端部署是一样的,我只是不想每次开电脑后再启动两个命令行界面。

我的服务器端较为复杂,前端由隧道服务端监听443端口分流到NGINX。我们的服务都是本地端口,且只有HTTP,因此还需要配置NGINX反代。钻研了一下午才搞定。

CPA & CPAM 配置

CPA

本文使用v7.1.25版本的CPA

服务器端配置和本地差不多,记得端口监听地址改为127.0.0.1即可。

CPAM

本文使用v1.5.1版本的CPAM,请核对好管理面板与CPAM可执行文件是否版本一致

CPAM有多种配置方案。具体参考CPA-Manager/README_CN.md at main · seakee/CPA-Manager

我选择的是使用systemd单文件运行的方式。实在不想重新拉Docker配置了。

同样设置监听地址为127.0.0.1

隧道服务端配置

如果隧道的域名和API地址域名一致,就不用考虑泛域名证书。否则,必须申请,因为隧道服务端不支持多个证书配置,只能选择单个域名证书或者泛域名证书。下面配置基于不同隧道域名与API域名地址,假设申请的泛域名证书是*.0d000721.xyz

首先设置fallback目标。这里任意设四个不同fallback目标,分别对应:

  • 隧道地址
  • 隧道地址h2
  • API地址
  • API地址h2

为什么要单独区分h2?因为后续开启WebSocket后会走HTTP/1.1进行Upgrade。

参考配置如下:

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
{
"settings": {
"fallbacks": [
{
"name": "tunnel.0d000721.xyz",
"dest": "127.0.0.1:8001",
"xver": 1
},
{
"name": "tunnel.0d000721.xyz",
"alpn": "h2",
"dest": "127.0.0.1:8002",
"xver": 1
},
{
"name": "api.0d000721.xyz",
"dest": "127.0.0.1:8003",
"xver": 1
},
{
"name": "api.0d000721.xyz",
"alpn": "h2",
"dest": "127.0.0.1:8004",
"xver": 1
}
]
}
}

NGINX 配置

NGINX 要同步监听上面配置写的fallback端口。隧道的配置不用管,保持即可,重点是配置新的API相关。

首先新建两个上游upstream,写在http块内,便于下面区分:

1
2
3
4
5
6
7
8
9
upstream cpa_backend {
server 127.0.0.1:8317;
keepalive 32; # 多保留一些连接以防高并发
}

upstream cpa_usage_backend {
server 127.0.0.1:18317;
keepalive 8; # 可以少一点 毕竟用量查询请求不多
}

在下面再加一块针对WebSocket的协议升级,不过NGINX初始配置应该自带了:

1
2
3
4
map $http_upgrade $connection_upgrade {
default upgrade;
"" "";
}

随后新创建一部分server监听。根据官方文档,将CPA用到的API地址和CPAM用到的API地址分别反代:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
server {

listen 127.0.0.1:8003 proxy_protocol;
listen 127.0.0.1:8004 http2 proxy_protocol;
server_name api.0d000721.xyz;

set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;

client_max_body_size 100m;

proxy_http_version 1.1;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $proxy_protocol_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Forwarded $proxy_add_forwarded;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

# 压缩设置
# 若未编译并加载zstd压缩模块则启用brotli/gzip
zstd_comp_level 3;
zstd_min_length 1024;
zstd_types
application/json
application/javascript
text/css
text/plain
text/xml
application/xml
application/xml+rss;

# brotli_comp_level 4;
# brotli_min_length 1024;
# brotli_types
# application/json
# application/javascript
# text/css
# text/plain
# text/xml
# application/xml
# application/xml+rss;

gzip_comp_level 5;
gzip_min_length 1024;
gzip_vary on;
gzip_proxied any;
gzip_types
application/json
application/javascript
text/css
text/plain
text/xml
application/xml
application/xml+rss;


# Codex Responses API:HTTP/SSE + WebSocket 都走 CPA
location = /v1/responses {
proxy_pass http://cpa_backend;

# server 层已经设置了 Upgrade / Connection / Host / X-Forwarded-* / timeout
# 这里不要单独只写一两个 proxy_set_header,否则会覆盖继承行为
proxy_request_buffering off;
}

# CPA-Manager / Usage Service 自己的接口
location = /health {
proxy_pass http://cpa_usage_backend;
}

location = /status {
proxy_pass http://cpa_usage_backend;
}

location = /setup {
proxy_pass http://cpa_usage_backend;
}

location ^~ /usage-service/ {
proxy_pass http://cpa_usage_backend;
}

# CPA HTTP 用量队列:必须交给 CPA 本体
location = /v0/management/usage-queue {
proxy_pass http://cpa_backend;
}

# CPA-Manager 提供的用量统计接口
location = /v0/management/usage {
proxy_pass http://cpa_usage_backend;
# brotli on;
zstd on;
gzip on;
}

location ^~ /v0/management/usage/ {
proxy_pass http://cpa_usage_backend;
# brotli on;
zstd on;
gzip on;
}

# CPA-Manager 提供的模型价格接口
location = /v0/management/model-prices {
proxy_pass http://cpa_usage_backend;
# brotli on;
zstd on;
gzip on;
}

location ^~ /v0/management/model-prices/ {
proxy_pass http://cpa_usage_backend;
# brotli on;
zstd on;
gzip on;
}

# CPA-Manager 提供的 API Key 别名接口
location = /v0/management/api-key-aliases {
proxy_pass http://cpa_usage_backend;
# brotli on;
zstd on;
gzip on;
}

location ^~ /v0/management/api-key-aliases/ {
proxy_pass http://cpa_usage_backend;
# brotli on;
zstd on;
gzip on;
}

# 其他管理 API 仍交给 CPA 本体
location ^~ /v0/management/ {
proxy_pass http://cpa_backend;
}

# /management.html 必须交给 CPA 本体,而不是 CPA-Manager
location = /management.html {
proxy_pass http://cpa_backend;
# brotli on;
zstd on;
gzip on;
}

# OpenAI 兼容 API、模型列表等默认走 CPA 本体
location / {
proxy_pass http://cpa_backend;
}
}

接着重启一下NGINX服务,访问https://api.0d000721.xyz/即可看到回应。管理面板在https://api.0d000721.xyz/management.html

登录管理面板后,首先需要进行CPA连接。不出意外的话会提示“当前面板由 Usage Service 托管”,我们只要填写CPA地址即可。

这里需要填写基于服务器本机的地址,如http://127.0.0.1:8317,而非暴露公网的https://api.0d000721.xyz!因为目前打开的是Usage Service的管理面板。理论上写https://api.0d000721.xyz也只是绕一圈,但别忘了我们上面没有为CPA和CPAM开启TLS,因此会出现协议错误的问题。只能老老实实写本地地址。

随后填一下CPA的管理密钥(非API密钥)。

WebSocket 配置

对于Codex而言,在~/.codex/config.toml下的模型配置中加一行:

1
supports_websockets = true

切换到WebSocket后体感快一点。