我以为剩下的只是把容器拉起来,后来才发现,真正要搭起来的是一台入口机。
这件事一开始其实很简单。
我想给自己留一个稳定的 Codex 入口,也顺手让身边几个人能一起用。直接把 CLIProxyAPI 扔到海外 VPS 上当然也能跑,但访问体验会飘;只放在国内机房,带宽和出海链路又是另一种不稳定。最后我选的不是“哪台机器最强”,而是一个更像分工的方案:腾讯云做入口,海外 VPS 做出口。
也就是说,这套叫 cpa.dongailin.cn 的东西,从一开始就不只是一个容器名。它是一个入口。
入口的要求跟单纯把服务跑起来完全不是一回事。客户端要有统一地址,管理后台要能开,认证文件要能加,用量页要能看,用户不能碰到裸端口,证书还得是正常的。光是把 CLIProxyAPI 监听在 127.0.0.1:8317,其实只完成了最内层的一小圈。
真正把它串起来之后,结构反而变得很清楚:
cpa.dongailin.cn
-> Caddy HTTPS reverse proxy
-> 127.0.0.1:8317
-> CLIProxyAPI
-> socks5://127.0.0.1:7897
-> zgo.2000521.xyz / 154.36.170.57
这套结构里,腾讯云那台机器不负责“直接翻出去”,它负责接住来自国内的访问,再把上游请求交给本机 Clash,最后从我已经稳定在跑的洛杉矶出口出去。这样做的好处很直接:入口在国内,访问延迟和证书都好处理;出口在海外,上游模型链路也能保持稳定。
我原本以为,真正费时间的部分会在 Docker Compose。
后来发现并不是。
第一个真正的转折点,是我意识到“后台能不能打开”这件事,本身就不是部署细节,而是系统是否成立的判断。CLIProxyAPI 跑起来之后,/management.html 最初还是不通,问题并不在管理功能没开,而在于静态面板文件根本没有被容器正确读取。后面补上 static 挂载和 MANAGEMENT_STATIC_PATH,再回头看,才会发现这类问题很典型:你以为自己在调一个页面,实际上你是在验证这套服务到底有没有成为“别人也能用”的系统。
第二个转折点更明显。
后台能打开之后,我又以为差不多了。结果第一次认真进 usage 页,页面直接卡住,甚至报出 Out of Memory。这个问题也很有代表性,因为它暴露的不是“机器小”,而是“你现在拿它当长期系统用了”。当请求记录开始累积,管理接口一次把大块 details[] 明细原样喂给前端,页面当然会撑不住。修这件事的时候,我反而第一次真正补齐了运维层:导出 usage、恢复 usage、定时备份、重启前自动恢复。到这里,这个 CPA 才不再像一个随时可能被重启清空的实验环境。
后面还有一个更隐蔽的问题,也让我很在意。
模型价格最初只是保存在浏览器本地 localStorage 里。这种做法在“一个人、一个浏览器、临时用用”时没有问题,可一旦你开始把它当成自己的正式入口,甚至让朋友一起接入,它就会立刻暴露出边界:换个浏览器,价格没了;换台机器,价格没了;看上去像是后台设置,实际上只是当前浏览器记住了这件事。最后我还是把这一块改成了后端统一保存,usage 页也因此能真正稳定地算出总花费,而不是把“请先设置模型价格”留给每一个新会话。
所以如果现在再回头看,这篇记录真正想说的,其实不是“我部署了 CLIProxyAPI”。
那只是起点。
真正完成的事情,是我把一个原本偏工具性的项目,改造成了一套可以长期使用的个人入口:根域名子站点、固定的 /v1 基地址、能自己加认证的管理后台、给 Codex CLI 用的教程首页、只开放 22/80/443 的暴露面、以及一套在出问题时还能恢复 usage 和价格配置的最小运维闭环。
这也是我这次最明确的一个判断:像 CLIProxyAPI 这种东西,装起来不难,难的是你什么时候愿意承认,“能跑”不等于“搭好”。
如果它只是你今晚临时验证一下的容器,那很多问题都可以先放着。可只要你开始把它当成一个稳定入口,给自己用,给朋友用,甚至把 cpa.dongailin.cn 这种域名真的公开出来,判断标准就会彻底变掉。你会开始在意证书、在意回环绑定、在意后台、在意重启后会不会丢数据、在意浏览器切换后配置还在不在。到了那个阶段,部署就不再是“把服务启动”,而是“把系统交付给未来的自己”。
我现在更愿意把这套 CPA 理解成后者。
它当然还是 CLIProxyAPI,还是 Docker,还是代理,还是反代。但真正让我觉得这件事做对了的,不是容器状态终于变成 Up,而是它已经从“我知道怎么开”变成了“我知道它为什么能长期开着”。
