<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Codex on BINGBlog</title><link>https://20.48.50.55.sslip.io/tags/codex/</link><description>Recent content in Codex on BINGBlog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Thu, 17 Sep 2026 13:10:00 +0800</lastBuildDate><atom:link href="https://20.48.50.55.sslip.io/tags/codex/index.xml" rel="self" type="application/rss+xml"/><item><title>一句话提示词：Codex 写出 3D 天气预报页</title><link>https://20.48.50.55.sslip.io/posts/2026-09-17-codex-3d-weather/</link><pubDate>Thu, 17 Sep 2026 13:10:00 +0800</pubDate><guid>https://20.48.50.55.sslip.io/posts/2026-09-17-codex-3d-weather/</guid><description>&lt;p&gt;给 Codex 发一句提示词，模型走服务器上的 CPA 网关（别名 &lt;code&gt;deepseek-flash&lt;/code&gt;，推理强度 high），19 分 59 秒后拿到一个能直接双击打开的单文件 3D 天气页。本文放上在线演示、实现要点，以及顺手做的「正文内嵌 HTML」验证。&lt;/p&gt;&#10;&lt;h2 id="一提示词与产出"&gt;&lt;a href="#%e4%b8%80%e6%8f%90%e7%a4%ba%e8%af%8d%e4%b8%8e%e4%ba%a7%e5%87%ba" class="header-anchor"&gt;&lt;/a&gt;一、提示词与产出&#10;&lt;/h2&gt;&lt;p&gt;提示词只有一句，没有补充任何设计稿或数据：&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="提示词原文" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://20.48.50.55.sslip.io/images/posts/codex-3d-weather/prompt.png"&gt;&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;项&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;值&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模型&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;deepseek-flash&lt;/code&gt;（CPA 网关别名，&lt;code&gt;codex --profile deepseek&lt;/code&gt;，reasoning high）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;耗时&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;19 分 59 秒&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;产出&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;单个 &lt;code&gt;index.html&lt;/code&gt;，52 KB&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;运行方式&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;three.js r160（jsdelivr CDN），无构建、无本地服务器，&lt;code&gt;file://&lt;/code&gt; 直接打开&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;武汉（30.59°N / 114.31°E）未来 7 天，Open-Meteo 抓取后写死在文件里&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="二在线演示"&gt;&lt;a href="#%e4%ba%8c%e5%9c%a8%e7%ba%bf%e6%bc%94%e7%a4%ba" class="header-anchor"&gt;&lt;/a&gt;二、在线演示&#10;&lt;/h2&gt;&lt;figure class="demo-embed"&gt;&#10; &lt;iframe src="https://20.48.50.55.sslip.io/demos/wuhan-weather-3d/index.html" title="武汉未来 7 天 3D 天气可视化（可交互）" loading="lazy" allowfullscreen&gt;&lt;/iframe&gt;&#10; &lt;figcaption class="demo-bar"&gt;&#10; &lt;span&gt;真实可交互页面（WebGL 实时渲染）&lt;/span&gt;&#10; &lt;a href="https://20.48.50.55.sslip.io/demos/wuhan-weather-3d/index.html" target="_blank" rel="noopener"&gt;全屏打开 ↗&lt;/a&gt;&#10; &lt;/figcaption&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;场景里的星空、镜面地面、泛光都是实时渲染的，不是贴图；演示页需要 WebGL，并从 CDN 拉 three.js。加载不出来时看下面的截图：&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="3D 天气预报页截图" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://20.48.50.55.sslip.io/images/posts/codex-3d-weather/preview.webp"&gt;&lt;/p&gt;&#10;&lt;h2 id="三数据怎么变成画面"&gt;&lt;a href="#%e4%b8%89%e6%95%b0%e6%8d%ae%e6%80%8e%e4%b9%88%e5%8f%98%e6%88%90%e7%94%bb%e9%9d%a2" class="header-anchor"&gt;&lt;/a&gt;三、数据怎么变成画面&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;视觉元素&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;编码的数据&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;柱体高度&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;当日气温（18–32℃ 映射到世界坐标）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;柱体颜色&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;温度色带：蓝 → 青 → 绿 → 黄 → 橙 → 红&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;柱顶亮点 / 底座光环&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;当日最高温 / 最低温&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;云团体积&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;云量（由 WMO 天气代码推出）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;雨丝密度&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;降水量&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;水平流线速度&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;风速&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;跨日发光带&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;每日温差区间：上沿最高温曲线，下沿最低温&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;底部日期卡&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;日期、天气、最高/最低温、温度条&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这层映射是模型自己定的，提示词里只给了「炫酷」两个字。&lt;/p&gt;&#10;&lt;h2 id="四实现要点"&gt;&lt;a href="#%e5%9b%9b%e5%ae%9e%e7%8e%b0%e8%a6%81%e7%82%b9" class="header-anchor"&gt;&lt;/a&gt;四、实现要点&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;单文件结构：&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; + &lt;code&gt;&amp;lt;script type=&amp;quot;importmap&amp;quot;&amp;gt;&lt;/code&gt; + &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt;，没有任何构建步骤&lt;/li&gt;&#10;&lt;li&gt;后处理：&lt;code&gt;EffectComposer&lt;/code&gt; + &lt;code&gt;UnrealBloomPass&lt;/code&gt; 泛光，ACES Filmic 色调映射&lt;/li&gt;&#10;&lt;li&gt;地面是 &lt;code&gt;Reflector&lt;/code&gt; 实时镜面反射，叠一层自定义着色器网格&lt;/li&gt;&#10;&lt;li&gt;云、雨、风、光柱都用自定义 &lt;code&gt;ShaderMaterial&lt;/code&gt; / Points，几何体经 &lt;code&gt;mergeGeometries&lt;/code&gt; 合并&lt;/li&gt;&#10;&lt;li&gt;HUD 是普通 DOM：底部 7 张日期卡、右侧单日明细（含逐小时气温 canvas）、左上信息牌、右上图例&lt;/li&gt;&#10;&lt;li&gt;数据写死在文件顶部 &lt;code&gt;DAYS&lt;/code&gt; / &lt;code&gt;HOURLY&lt;/code&gt; 常量，换城市只改 &lt;code&gt;CITY&lt;/code&gt; 与这两个数组&lt;/li&gt;&#10;&lt;li&gt;交互：&lt;code&gt;OrbitControls&lt;/code&gt; 轨道相机，点柱子或日期卡选中单日，&lt;code&gt;←/→&lt;/code&gt; 切换，空格视角漂移&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="五正文内嵌-html-的验证"&gt;&lt;a href="#%e4%ba%94%e6%ad%a3%e6%96%87%e5%86%85%e5%b5%8c-html-%e7%9a%84%e9%aa%8c%e8%af%81" class="header-anchor"&gt;&lt;/a&gt;五、正文内嵌 HTML 的验证&#10;&lt;/h2&gt;&lt;p&gt;结论：可以。本站的 goldmark 渲染器开着 &lt;code&gt;unsafe = true&lt;/code&gt;（&lt;code&gt;config/_default/markup.toml&lt;/code&gt;），Markdown 里的原始 HTML 原样输出，上面的演示就是直接嵌进正文的 &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;能力&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;结果&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;行内标签（&lt;code&gt;&amp;lt;kbd&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;生效&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; 内联样式&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;生效&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; 嵌同站静态页&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;生效&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; 折叠块&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;生效&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;嵌别的站点&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;被 &lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt; 挡掉，只影响别人嵌我们&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;样式作用域&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;必须套自己的容器 class，否则会污染整站&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;演示页放在 &lt;code&gt;static/demos/wuhan-weather-3d/index.html&lt;/code&gt;，Hugo 原样复制到站点根目录，nginx 当普通静态页返回。&lt;/p&gt;&#10;&lt;details&gt;&#10;&lt;summary&gt;展开看这段演示的原始 HTML 写法&lt;/summary&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;figure&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;demo-embed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/demos/wuhan-weather-3d/index.html&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;武汉未来 7 天 3D 天气可视化（可交互）&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;lazy&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;allowfullscreen&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;figcaption&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;demo-bar&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;真实可交互页面（WebGL 实时渲染）&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/demos/wuhan-weather-3d/index.html&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;_blank&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;noopener&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;全屏打开 ↗&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;figcaption&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;样式写在 &lt;code&gt;assets/scss/custom.scss&lt;/code&gt; 的 &lt;code&gt;.demo-embed&lt;/code&gt; 里，&lt;code&gt;iframe&lt;/code&gt; 用 &lt;code&gt;aspect-ratio&lt;/code&gt; 控制高度。注意主题给 &lt;code&gt;figure&lt;/code&gt; 加了铺满卡片的负外边距：自定义样式只改上下间距、别用 &lt;code&gt;margin&lt;/code&gt; 简写覆盖，否则外边距被重置、加宽的 &lt;code&gt;width&lt;/code&gt; 还在，块就会向右溢出被裁切。&lt;/p&gt;&#10;&lt;/details&gt;&#10;&lt;h2 id="小结"&gt;&lt;a href="#%e5%b0%8f%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;小结&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;一句提示词 + 推理强度 high 的模型，20 分钟拿到能用的单文件可视化页面&lt;/li&gt;&#10;&lt;li&gt;效果取决于数据映射想没想清楚：柱高对气温、云量对云团体积、降水对雨丝密度&lt;/li&gt;&#10;&lt;li&gt;产物零依赖、零构建，&lt;code&gt;file://&lt;/code&gt; 双击即开，部署时当一个静态文件丢出去即可&lt;/li&gt;&#10;&lt;li&gt;博客正文支持原始 HTML：本站 goldmark 已开 &lt;code&gt;unsafe&lt;/code&gt;，&lt;code&gt;iframe&lt;/code&gt; / &lt;code&gt;style&lt;/code&gt; / &lt;code&gt;details&lt;/code&gt; 都能用&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt; 只允许嵌本站资源，需要嵌外站就得改响应头&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>用 CLIProxyAPI 在服务器搭多上游统一网关</title><link>https://20.48.50.55.sslip.io/posts/2026-09-17-codex-cpa-gateway/</link><pubDate>Thu, 17 Sep 2026 01:30:00 +0800</pubDate><guid>https://20.48.50.55.sslip.io/posts/2026-09-17-codex-cpa-gateway/</guid><description>&lt;p&gt;同时用几个 AI 上游很麻烦：每个都要单独配 key、单独改客户端，额度也各管各的。用 CLIProxyAPI 在服务器上把它们聚合成一个端点，对外只给一把 key，客户端改个 &lt;code&gt;base_url&lt;/code&gt; 就能用，&lt;code&gt;/model&lt;/code&gt; 随时切模型。下面是完整部署流程，新服务器按顺序执行即可。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="整体链路" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://20.48.50.55.sslip.io/images/posts/codex-cpa-gateway/architecture.svg"&gt;&lt;/p&gt;&#10;&lt;h2 id="适用场景"&gt;&lt;a href="#%e9%80%82%e7%94%a8%e5%9c%ba%e6%99%af" class="header-anchor"&gt;&lt;/a&gt;适用场景&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;多上游自用&lt;/strong&gt;：官方 OAuth 与第三方 API 共用一个 &lt;code&gt;base_url&lt;/code&gt;，&lt;code&gt;/model&lt;/code&gt; 切模型不用改配置；服务器在境外且国内可直连（本文是日本节点）时，客户端也不必自己再挂代理&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;对外分发&lt;/strong&gt;：账号额度用不完（比如 GPT Pro 20x），装到服务器上就能公网分发——本机版只能服务自己或局域网，一把 key 给团队 / 朋友，不用再搭 VPN&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;多客户端复用&lt;/strong&gt;：Codex、Claude Code、Gemini CLI、Cursor 等共用同一把 key，新增或替换上游时客户端不动&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="一准备"&gt;&lt;a href="#%e4%b8%80%e5%87%86%e5%a4%87" class="header-anchor"&gt;&lt;/a&gt;一、准备&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;项&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;说明&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;服务器&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;能跑 nginx 的 Linux（本文 Ubuntu 24.04），CPA 常驻内存约 57MB&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;域名 + 证书&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;反代必须有 HTTPS；没有就用 &lt;code&gt;certbot --nginx -d 你的域名&lt;/code&gt; 申请&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nginx&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;反代与鉴权都在这一层&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;上游账号（可选）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ChatGPT / Claude / xAI / Kimi 等任一，用于 OAuth 登录&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;第三方 Key（可选）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;DeepSeek 等 OpenAI 兼容服务，官方额度用完后接管&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;版本：CPA &lt;code&gt;v7.3.4&lt;/code&gt;、codex-cli &lt;code&gt;0.154.0&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h2 id="二安装-cpa"&gt;&lt;a href="#%e4%ba%8c%e5%ae%89%e8%a3%85-cpa" class="header-anchor"&gt;&lt;/a&gt;二、安装 CPA&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL -o cpa.tar.gz &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://github.com/router-for-me/CLIProxyAPI/releases/download/v7.3.4/CLIProxyAPI_7.3.4_linux_amd64.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tar xzf cpa.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p ~/cliproxyapi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;install -m &lt;span class="m"&gt;0755&lt;/span&gt; cli-proxy-api ~/cliproxyapi/cli-proxy-api&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;单文件 Go 程序，约 64MB。用 systemd 托管：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/systemd/system/cli-proxy-api.service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;CLIProxyAPI - unified upstream gateway&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Wants&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;azureuser # 改成你的运行用户&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/azureuser/cliproxyapi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/azureuser/cliproxyapi/cli-proxy-api -config /home/azureuser/.cli-proxy-api/config.yaml&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;RestartSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;MemoryMax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;384M&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl daemon-reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now cli-proxy-api&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="三写配置"&gt;&lt;a href="#%e4%b8%89%e5%86%99%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;三、写配置&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;~/.cli-proxy-api/config.yaml&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 只监听本机：公网必须先过 nginx&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8317&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;remote-management&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;allow-remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 反代场景建议 true&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secret-key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;管理密钥&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 明文填，启动时自动 bcrypt 加密回写&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;auth-dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/home/azureuser/.cli-proxy-api&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# OAuth 凭证目录&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;api-keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 客户端访问 CPA 用的密钥&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;sk-cpa-xxxxxxxx&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;三个关键点：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;host&lt;/code&gt; 绑 &lt;code&gt;127.0.0.1&lt;/code&gt;，公网只能从 nginx 进&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;secret-key&lt;/code&gt; 管管理接口，&lt;code&gt;api-keys&lt;/code&gt; 管客户端调用，两者别混&lt;/li&gt;&#10;&lt;li&gt;上游 provider 全部在&lt;strong&gt;管理面板&lt;/strong&gt;里配，配置文件保持干净&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="四登录上游账号"&gt;&lt;a href="#%e5%9b%9b%e7%99%bb%e5%bd%95%e4%b8%8a%e6%b8%b8%e8%b4%a6%e5%8f%b7" class="header-anchor"&gt;&lt;/a&gt;四、登录上游账号&#10;&lt;/h2&gt;&lt;p&gt;CPA 内置多种 OAuth 登录，按需挑：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;上游&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;命令&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ChatGPT / Codex&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-codex-device-login&lt;/code&gt;（服务器）、&lt;code&gt;-codex-login&lt;/code&gt;（本机浏览器）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Claude&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-claude-login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;xAI&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-xai-login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Kimi&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-kimi-login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Meta&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-meta-login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Devin&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-devin-login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Antigravity&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-antigravity-login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Google Vertex&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;-vertex-import 服务账号.json&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;以无浏览器的服务器为例，用设备码登录 Codex：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./cli-proxy-api -config ~/.cli-proxy-api/config.yaml -codex-device-login&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Codex device URL: https://auth.openai.com/codex/device&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Codex device code: XXXX-XXXX&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开网址输码授权，凭证落到 &lt;code&gt;auth-dir&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;当然也可以直接在 &lt;strong&gt;Web 面板&lt;/strong&gt;里点「认证文件 → 对应上游 → 发起登录」。OAuth 回调端口被占用时用 &lt;code&gt;-oauth-callback-port&lt;/code&gt; 指定，无浏览器加 &lt;code&gt;-no-browser&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;⚠️ &lt;strong&gt;不要照搬&lt;/strong&gt;教程里的 &lt;code&gt;forced_login_method = &amp;quot;api&amp;quot;&lt;/code&gt; / &lt;code&gt;preferred_auth_method = &amp;quot;apikey&amp;quot;&lt;/code&gt;：已有 ChatGPT 登录态时，Codex 会判定「要用 API key 登录」，登出并删掉 &lt;code&gt;auth.json&lt;/code&gt;。加 provider 只靠 &lt;code&gt;env_key&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="五nginx-反代分发核心"&gt;&lt;a href="#%e4%ba%94nginx-%e5%8f%8d%e4%bb%a3%e5%88%86%e5%8f%91%e6%a0%b8%e5%bf%83" class="header-anchor"&gt;&lt;/a&gt;五、nginx 反代分发（核心）&#10;&lt;/h2&gt;&lt;p&gt;CPA 只监听本机，对外必须经 nginx。策略：&lt;strong&gt;隐藏路径 + Basic Auth + 限速&lt;/strong&gt;，三条路径分开管面板页、管理 API、客户端 API。&lt;/p&gt;&#10;&lt;h3 id="1-建账号密码"&gt;&lt;a href="#1-%e5%bb%ba%e8%b4%a6%e5%8f%b7%e5%af%86%e7%a0%81" class="header-anchor"&gt;&lt;/a&gt;1. 建账号密码&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo htpasswd -c /etc/nginx/.htpasswd-cpa cpadmin &lt;span class="c1"&gt;# 没有 htpasswd 就先装 apache2-utils&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-写反代片段"&gt;&lt;a href="#2-%e5%86%99%e5%8f%8d%e4%bb%a3%e7%89%87%e6%ae%b5" class="header-anchor"&gt;&lt;/a&gt;2. 写反代片段&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/nginx/snippets/cpa.conf（用 include 引入 server 块）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 限速区（放 http 块；已定义过就跳过）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;limit_req_zone&lt;/span&gt; &lt;span class="nv"&gt;$binary_remote_addr&lt;/span&gt; &lt;span class="s"&gt;zone=admin_zone:10m&lt;/span&gt; &lt;span class="s"&gt;rate=10r/m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/cpa-adm-XXXXXXXX&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;/cpa-adm-XXXXXXXX/management.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/cpa-adm-XXXXXXXX/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;/cpa-adm-XXXXXXXX/management.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ① 面板静态页：Basic Auth + 限速&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="s"&gt;^~&lt;/span&gt; &lt;span class="s"&gt;/cpa-adm-XXXXXXXX/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;auth_basic&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;CPA&lt;/span&gt; &lt;span class="s"&gt;Admin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;auth_basic_user_file&lt;/span&gt; &lt;span class="s"&gt;/etc/nginx/.htpasswd-cpa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;limit_req&lt;/span&gt; &lt;span class="s"&gt;zone=admin_zone&lt;/span&gt; &lt;span class="s"&gt;burst=60&lt;/span&gt; &lt;span class="s"&gt;nodelay&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8317/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# SSE / 流式必需&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="s"&gt;3600s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# 长任务别被 60s 掐断&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;client_max_body_size&lt;/span&gt; &lt;span class="mi"&gt;200m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ② 管理 API：面板默认就调这里，鉴权交给 CPA&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="s"&gt;^~&lt;/span&gt; &lt;span class="s"&gt;/v0/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8317/v0/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ③ 客户端 API：隐藏路径 + api-key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="s"&gt;^~&lt;/span&gt; &lt;span class="s"&gt;/cpa-api-XXXXXXXX/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8317/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="s"&gt;3600s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;client_max_body_size&lt;/span&gt; &lt;span class="mi"&gt;200m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;XXXXXXXX&lt;/code&gt; 换成自己的随机串（路径本身就是一层防护）。没有现成 server 块的话，最小骨架：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;你的域名&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="s"&gt;/etc/letsencrypt/live/你的域名/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="s"&gt;/etc/letsencrypt/live/你的域名/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="s"&gt;/etc/nginx/snippets/cpa.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-为什么要拆路径"&gt;&lt;a href="#3-%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e6%8b%86%e8%b7%af%e5%be%84" class="header-anchor"&gt;&lt;/a&gt;3. 为什么要拆路径&#10;&lt;/h3&gt;&lt;p&gt;nginx 的 &lt;code&gt;auth_basic&lt;/code&gt; 用 &lt;code&gt;Authorization: Basic ...&lt;/code&gt; 认证，而 CPA 面板用 &lt;code&gt;Authorization: Bearer &amp;lt;管理密钥&amp;gt;&lt;/code&gt; 调 API（&lt;code&gt;management.html&lt;/code&gt; 里写死了 &lt;code&gt;Bearer ${managementKey}&lt;/code&gt;）。两者共用同一个头：Bearer 会顶掉 Basic，&lt;code&gt;auth_basic&lt;/code&gt; 直接 401；用变量喂空值也不会关闭认证（实测返回 &lt;code&gt;realm=&amp;quot;&amp;quot;&lt;/code&gt; 的 401）。&lt;/p&gt;&#10;&lt;p&gt;所以面板页归 Basic Auth，管理 API 走一条不带 &lt;code&gt;auth_basic&lt;/code&gt; 的路径，由 CPA 自己校验密钥；客户端 API 再走一条隐藏路径：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;路径&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;用途&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;鉴权&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/cpa-adm-XXXXXXXX/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;面板静态页&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Basic Auth&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/v0/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;管理 API（面板默认调用）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CPA 管理密钥（Bearer）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/cpa-api-XXXXXXXX/v1/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;客户端 API&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CPA api-key（Bearer）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="4-面板默认服务地址不带路径"&gt;&lt;a href="#4-%e9%9d%a2%e6%9d%bf%e9%bb%98%e8%ae%a4%e6%9c%8d%e5%8a%a1%e5%9c%b0%e5%9d%80%e4%b8%8d%e5%b8%a6%e8%b7%af%e5%be%84" class="header-anchor"&gt;&lt;/a&gt;4. 面板默认服务地址不带路径&#10;&lt;/h3&gt;&lt;p&gt;面板取的是 &lt;code&gt;window.location&lt;/code&gt; 里不带路径的协议 + 域名 + 端口：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;$f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Zf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;//&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="sb"&gt;`:&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;所以请求会打到 &lt;code&gt;https://域名/v0/management/...&lt;/code&gt;（根路径），而不是 &lt;code&gt;/cpa-mgmt-.../&lt;/code&gt; 下的那条。这样配会 404，nginx 日志里能看到 &lt;code&gt;/v0/management/config&lt;/code&gt; 没有路由。&lt;/p&gt;&#10;&lt;p&gt;两个解法：面板里手动把服务地址填全，或在 nginx 补一条根路径 &lt;code&gt;/v0/&lt;/code&gt; 路由。上面片段用的是后者。&lt;/p&gt;&#10;&lt;p&gt;改完检查并重载：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nginx -t &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo systemctl reload nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="六接入第三方-api以-deepseek-为例"&gt;&lt;a href="#%e5%85%ad%e6%8e%a5%e5%85%a5%e7%ac%ac%e4%b8%89%e6%96%b9-api%e4%bb%a5-deepseek-%e4%b8%ba%e4%be%8b" class="header-anchor"&gt;&lt;/a&gt;六、接入第三方 API（以 DeepSeek 为例）&#10;&lt;/h2&gt;&lt;p&gt;登录面板（&lt;code&gt;https://域名/cpa-adm-XXXXXXXX/management.html&lt;/code&gt;）后，在「提供商」里加一条 OpenAI 兼容：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;字段&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;值&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;名称&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;deepseek&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;base-url&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;https://api.deepseek.com&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;api-key&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;DeepSeek 的 &lt;code&gt;sk-...&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模型&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;deepseek-flash&lt;/code&gt;（要更大就再加 &lt;code&gt;deepseek-v4-pro&lt;/code&gt;）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;code&gt;base-url&lt;/code&gt; 带不带 &lt;code&gt;/v1&lt;/code&gt; 都行；&lt;code&gt;alias&lt;/code&gt; 留空会用 &lt;code&gt;name&lt;/code&gt; 当模型名。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;任何 OpenAI 兼容服务同理：填 &lt;code&gt;base-url&lt;/code&gt; + &lt;code&gt;api-key&lt;/code&gt; 即可，官方 OAuth 与这些第三方模型会一起出现在 &lt;code&gt;/v1/models&lt;/code&gt; 里。保存后面板会把配置写回 &lt;code&gt;config.yaml&lt;/code&gt; 并热重载，无需重启。&lt;/p&gt;&#10;&lt;h2 id="七验证"&gt;&lt;a href="#%e4%b8%83%e9%aa%8c%e8%af%81" class="header-anchor"&gt;&lt;/a&gt;七、验证&#10;&lt;/h2&gt;&lt;p&gt;三种协议各测一遍（走公网入口）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://域名/cpa-api-XXXXXXXX/v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-cpa-xxxxxxxx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1) 模型列表（官方 OAuth 与第三方模型的合集）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/models&amp;#34;&lt;/span&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$KEY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2) OpenAI 协议&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/chat/completions&amp;#34;&lt;/span&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$KEY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;model&amp;#34;:&amp;#34;deepseek-flash&amp;#34;,&amp;#34;messages&amp;#34;:[{&amp;#34;role&amp;#34;:&amp;#34;user&amp;#34;,&amp;#34;content&amp;#34;:&amp;#34;回复：A-OK&amp;#34;}]}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# → A-OK&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 3) Responses 协议（Codex 用的就是它）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/responses&amp;#34;&lt;/span&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$KEY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;model&amp;#34;:&amp;#34;deepseek-flash&amp;#34;,&amp;#34;input&amp;#34;:&amp;#34;回复：R-OK&amp;#34;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;鉴权矩阵（都应满足）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;面板页 无认证 → 401&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;面板页 Basic → 200&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;管理API 正确 Bearer → 200&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;管理API 错误/无 密钥 → 401&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;分发API 正确 key → 200&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;分发API 无 key → 401&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="八客户端接入"&gt;&lt;a href="#%e5%85%ab%e5%ae%a2%e6%88%b7%e7%ab%af%e6%8e%a5%e5%85%a5" class="header-anchor"&gt;&lt;/a&gt;八、客户端接入&#10;&lt;/h2&gt;&lt;p&gt;Codex 指向 CPA（&lt;code&gt;~/.codex/config.toml&lt;/code&gt;）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;model_provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cpa&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gpt-5.6-sol&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;model_providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cpa&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CPA&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;http://127.0.0.1:8317/v1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;experimental_bearer_token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sk-cpa-xxxxxxxx&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;wire_api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;responses&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;supports_websockets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;/model&lt;/code&gt; 里会同时出现官方 OAuth 的模型和第三方模型，额度用光时切过去，会话不断。&lt;/p&gt;&#10;&lt;p&gt;分发给其他客户端（同一把 key）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# OpenAI 兼容&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OPENAI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; https://域名/cpa-api-XXXXXXXX/v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; sk-cpa-xxxxxxxx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Claude Code&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;ANTHROPIC_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://域名/cpa-api-XXXXXXXX&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;ANTHROPIC_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sk-cpa-xxxxxxxx&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="九安全与分发建议"&gt;&lt;a href="#%e4%b9%9d%e5%ae%89%e5%85%a8%e4%b8%8e%e5%88%86%e5%8f%91%e5%bb%ba%e8%ae%ae" class="header-anchor"&gt;&lt;/a&gt;九、安全与分发建议&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;CPA 只绑 &lt;code&gt;127.0.0.1&lt;/code&gt;，公网必须过 nginx（HTTPS）&lt;/li&gt;&#10;&lt;li&gt;面板页 Basic Auth + 管理密钥双因素；管理 API 连续 5 次失败封禁约 30 分钟&lt;/li&gt;&#10;&lt;li&gt;客户端 API 只靠 api-key，可随时增删（泄露一个删一个）&lt;/li&gt;&#10;&lt;li&gt;隐藏路径 + 限速，降低被扫概率&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;风险&lt;/strong&gt;：分发出去的官方模型请求烧的是自己账号的额度，给的人越多越可能封号。分发给不熟的人，建议只发第三方付费模型（按量计费）或加 IP 白名单。&lt;/p&gt;&#10;&lt;h2 id="附录为什么需要这层网关"&gt;&lt;a href="#%e9%99%84%e5%bd%95%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e8%bf%99%e5%b1%82%e7%bd%91%e5%85%b3" class="header-anchor"&gt;&lt;/a&gt;附录：为什么需要这层网关&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;/model&lt;/code&gt; 弹出的是当前 provider 的模型目录，切的是模型 slug，不是 provider。翻 Codex 源码可确认：&lt;code&gt;ModelPreset&lt;/code&gt; 没有 provider 字段。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ModelPreset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;: &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 只有模型 slug&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;display_name&lt;/span&gt;: &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ... 没有 provider&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会话里 provider 固定，想在多个上游之间切只有两条路：退出后用不同 &lt;code&gt;--profile&lt;/code&gt; 重开，或&lt;strong&gt;把上游合成一个 provider&lt;/strong&gt;——后者就是第 2–6 节做的事。&lt;/p&gt;&#10;&lt;h2 id="小结"&gt;&lt;a href="#%e5%b0%8f%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;小结&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;部署顺序：装 CPA → 写配置 → 登录上游 → nginx 反代 → 加第三方 API → 验证&lt;/li&gt;&#10;&lt;li&gt;登录方式按上游选：Codex 用设备码，Claude/xAI/Kimi 等用对应 &lt;code&gt;-xxx-login&lt;/code&gt;，Vertex 导入服务账号&lt;/li&gt;&#10;&lt;li&gt;反代必须拆路径：面板页走 Basic Auth，管理/客户端 API 走 Bearer&lt;/li&gt;&#10;&lt;li&gt;面板默认服务地址不带路径，记得补 &lt;code&gt;/v0/&lt;/code&gt; 路由&lt;/li&gt;&#10;&lt;li&gt;网关让客户端只配一个 &lt;code&gt;base_url&lt;/code&gt; 就能跨上游切换；对外分发的额度风险要提前评估&lt;/li&gt;&#10;&lt;/ol&gt;&#10;</description></item></channel></rss>