<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AI 网关 on 我的博客</title><link>https://blog.5616760.com/tags/ai-%E7%BD%91%E5%85%B3/</link><description>Recent content in AI 网关 on 我的博客</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Mon, 28 Sep 2026 19:40:00 +0800</lastBuildDate><atom:link href="https://blog.5616760.com/tags/ai-%E7%BD%91%E5%85%B3/index.xml" rel="self" type="application/rss+xml"/><item><title>agent2api 一键安装器：一条命令装起带 HTTPS 的本地 AI 网关</title><link>https://blog.5616760.com/0024.html</link><pubDate>Mon, 28 Sep 2026 19:40:00 +0800</pubDate><guid>https://blog.5616760.com/0024.html</guid><description>&#10; &lt;blockquote&gt;&#10; &lt;p&gt;本文整理自爱搜资源网的文章（作者 Isoziyuan）：&lt;a class="link" href="https://isoziyuan.com/p/100171/" target="_blank" rel="noopener"&#10; &gt;https://isoziyuan.com/p/100171/&lt;/a&gt;，内容为该项目 &lt;code&gt;install-agent2api.sh&lt;/code&gt; 安装脚本的使用说明与实测记录。脚本版本 v1.7.0，源码与回归套件见文末。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="一句话"&gt;一句话&#10;&lt;/h2&gt;&lt;p&gt;把 agent2api 装到你的服务器上，一条命令。它是本地网关——把 WorkBuddy、Qoder、Cline 这类客户端的转成 OpenAI 兼容接口，自己管多账号、模型路由和出网。脚本会&lt;strong&gt;自动挑空闲端口&lt;/strong&gt;、想绑域名就&lt;strong&gt;自动申请 Let&amp;rsquo;s Encrypt 证书&lt;/strong&gt;、自动认你机器上已有的 Caddy 并接好反代。&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR&#10; C["AI 客户端&lt;br/&gt;WorkBuddy / Qoder / Cline …"] --&gt;|"base_url：https://域名/v1&lt;br/&gt;api_key：网关 Key"| G["agent2api 网关 /v1"]&#10; G --&gt; U["上游账号池&lt;br/&gt;（面板「账号」里登记）"]&#10; P["管理面板 https://域名/"] -.-&gt; G&#10; style C fill:#2d6cdf,stroke:#1c4a9e,color:#fff&#10; style G fill:#3a7d44,stroke:#245c2c,color:#fff&#10; style U fill:#7a4fbf,stroke:#553394,color:#fff&#10; style P fill:#8a6d3b,stroke:#5f4a25,color:#fff&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在 VPS 上粘这一行就装完了 —— 不用先在本地下载再 scp 上传&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -fsSL &lt;span style="color:#e6db74"&gt;&amp;#34;https://pan.ailxw.com/api/pickup-download?code=20818&amp;#34;&lt;/span&gt; -o ~/a2a.sh &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash ~/a2a.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;提示符是 &lt;code&gt;#&lt;/code&gt;（登录就是 root，多数 VPS 默认如此）就用上面这条；是 &lt;code&gt;$&lt;/code&gt;（普通用户）就把最后的 &lt;code&gt;bash&lt;/code&gt; 换成 &lt;code&gt;sudo bash&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;别习惯性加 &lt;code&gt;sudo&lt;/code&gt; —— 很多精简镜像根本没装 sudo，加了会报 &lt;code&gt;sudo: command not found&lt;/code&gt;，后面还跟一个 &lt;code&gt;curl: (23) Failed writing body&lt;/code&gt;，看着像网络问题，其实是 sudo 不存在。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;它只动三处：起一个 docker 容器、往 Caddyfile 里加一段&lt;strong&gt;带标记的&lt;/strong&gt;站点块（&lt;code&gt;--no-domain&lt;/code&gt; 可一键摘掉）、在安装目录写几个文件。改反代配置前先备份、改完先校验、失败自动回滚；原有站点全程不受影响。&lt;/p&gt;&#10;&lt;p&gt;注意是&lt;strong&gt;在 VPS 上执行&lt;/strong&gt;，不是在你自己的电脑上。粘上去如果没反应，说明这个下载源不通，文末「下载」一节有三个备用源。&lt;/p&gt;&#10;&lt;h2 id="装完之后会得到什么"&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;&lt;code&gt;https://你的域名/&lt;/code&gt;（不绑域名时走 SSH 隧道，见下文）&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;https://你的域名/v1&lt;/code&gt;，客户端 &lt;code&gt;base_url&lt;/code&gt; 填它（不绑域名时是 &lt;code&gt;http://127.0.0.1:&amp;lt;网关端口&amp;gt;/v1&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;Let&amp;rsquo;s Encrypt 自动签发 + 自动续期（Caddy 负责）&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;单容器 + 可选一个自建 Caddy 容器；内存上限默认 384m&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;data/&lt;/code&gt;），删目录即彻底清理&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="最常用的四条命令"&gt;最常用的四条命令&#10;&lt;/h3&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;code&gt;sudo bash install-agent2api.sh&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;sudo bash install-agent2api.sh --dry-run&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;sudo bash install-agent2api.sh --yes --domain a2a.example.com&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;sudo bash install-agent2api.sh --uninstall&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;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="装完之后的运维"&gt;装完之后的运维&#10;&lt;/h3&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;code&gt;--status&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;--check-update&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;查 Docker Hub 上有没有新版本&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;--upgrade&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;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="域名与反代相关"&gt;域名与反代相关&#10;&lt;/h3&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;code&gt;--domain &amp;lt;域名&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;--no-domain&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;--expose both|panel|gateway&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;域名下暴露什么（默认 both，&lt;code&gt;/v1*&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;code&gt;--caddy-mode host|docker|self&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;--cf y|n&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;域名是否走 Cloudflare 橙云（自动加真实 IP 还原）&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;--dir&lt;/code&gt; 安装目录、&lt;code&gt;--tag&lt;/code&gt; 镜像版本、&lt;code&gt;--panel-port&lt;/code&gt; / &lt;code&gt;--gateway-port&lt;/code&gt; 指定端口、&lt;code&gt;--mem&lt;/code&gt; 内存上限、&lt;code&gt;--lock-register&lt;/code&gt; / &lt;code&gt;--open-register&lt;/code&gt; 注册开关、&lt;code&gt;--with-manager&lt;/code&gt; 登记为 workbuddy-manager 的上游。&lt;/p&gt;&#10;&lt;h3 id="关于升级有个坑值得先说"&gt;关于升级，有个坑值得先说&#10;&lt;/h3&gt;&lt;p&gt;agent2api 面板里那个「立即更新」按钮在 Docker 部署下是&lt;strong&gt;用不了的&lt;/strong&gt;——它去 GitHub Releases 下载，而那个仓库的 Releases 里只有桌面端安装包（&lt;code&gt;.dmg&lt;/code&gt; 和 &lt;code&gt;setup.exe&lt;/code&gt;），没有任何 Linux 产物。面板自己也会提示「请通过 Docker 镜像更新」。&lt;/p&gt;&#10;&lt;p&gt;所以升级只能换镜像，&lt;code&gt;--upgrade&lt;/code&gt; 干的就是这件事：改 compose 里的镜像 tag → 拉取 → 重建 → 等 healthy → 从容器内部复核两个端口，任何一步不过就&lt;strong&gt;自动回滚旧版本&lt;/strong&gt;并把状态文件也一起还原。&lt;/p&gt;&#10;&lt;h2 id="为什么写成--o-文件--bash-文件而不是-curl---bash"&gt;为什么写成 &lt;code&gt;-o 文件 &amp;amp;&amp;amp; bash 文件&lt;/code&gt;，而不是 &lt;code&gt;curl … | bash&lt;/code&gt;&#10;&lt;/h2&gt;&lt;p&gt;这两种写法作者都试过，各有一个坑，而且都是&amp;quot;看起来在跑、其实没跑对&amp;quot;：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;坑一：管道会把 stdin 占掉。&lt;/strong&gt; 安装器默认是交互式的，&lt;code&gt;curl | bash&lt;/code&gt; 时它读不到你的键盘。&lt;code&gt;bash install.sh &amp;lt; /dev/null&lt;/code&gt; 跑出来，它一个都不问、&lt;strong&gt;静默全部采用默认值&lt;/strong&gt;往下装——你以为在交互，其实配置项你一个都没选过。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;坑二：管道失败是无声的。&lt;/strong&gt; &lt;code&gt;curl -fsSL … | bash&lt;/code&gt; 里如果源不通，&lt;code&gt;-f&lt;/code&gt; 让 curl 不输出错误体、&lt;code&gt;-s&lt;/code&gt; 让它不输出进度，于是 curl 什么都不打印、bash 收到空输入，你屏幕上什么都不会出现。国内访问 &lt;code&gt;cdn.jsdelivr.net&lt;/code&gt; 经常不通，症状就是&amp;quot;粘上去没反应&amp;quot;。&lt;/p&gt;&#10;&lt;p&gt;改成 &lt;code&gt;-o 文件 &amp;amp;&amp;amp; bash 文件&lt;/code&gt;：出错会打印原因、&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 会拦住后续、stdin 还是你的终端，交互正常。&lt;/p&gt;&#10;&lt;p&gt;还有个副作用：&lt;code&gt;curl … | bash&lt;/code&gt; 会让 &lt;code&gt;$0&lt;/code&gt; 变成 &lt;code&gt;bash&lt;/code&gt;。实测 &lt;code&gt;echo 'echo $0' | bash&lt;/code&gt; 输出 &lt;code&gt;bash&lt;/code&gt;，存成文件执行输出的才是文件路径。安装器要用自身路径打印&amp;quot;以后怎么重跑 / 怎么卸载&amp;quot;，管道执行会让它打出 &lt;code&gt;bash bash --uninstall&lt;/code&gt; 这种没法用的东西。&lt;/p&gt;&#10;&lt;h2 id="首次使用四步"&gt;首次使用四步&#10;&lt;/h2&gt;&lt;p&gt;打开面板注册管理员 → 「账号」里加上游账号 → 「网关 Key」建一把 Key → 客户端 &lt;code&gt;base_url&lt;/code&gt; 填 &lt;code&gt;https://你的域名/v1&lt;/code&gt;、&lt;code&gt;api_key&lt;/code&gt; 填那把 Key。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;面板实际支持 14 种上游账号（WorkBuddy / 小浣熊 / Qoder / Trae / Cline / Accio / ZCode / CatPaw / CodeArts…），脚本会直接列在提示里。少了&amp;quot;加上游账号&amp;quot;这一步，客户端拿不到任何模型。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;自助注册默认是开着的&lt;/strong&gt;——直接在浏览器里打开面板就能注册，不用绕隧道。但有个必须知道的背景：agent2api 的规则是「第一个打开面板的人注册成管理员」，而域名签了证书就会进 Certificate Transparency 日志、被公开索引。也就是说，从面板上线到你注册完成之间，&lt;strong&gt;谁先打开谁就是管理员&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;所以脚本装完会检测管理员注册了没，没注册就醒目提醒：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;× 管理员还没注册 —— 现在任何人打开面板都能抢注成管理员，请立刻去注册！&#10; 立刻打开：https://你的域名/&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;看到这行就去注册，注册完再干别的。想更稳妥就封掉：重跑加 &lt;code&gt;--lock-register&lt;/code&gt;，注册端点返回 403，注册改走 SSH 隧道（隧道直连容器、不经过 Caddy，不受该规则影响）。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;注意&lt;strong&gt;两个端口都要转发&lt;/strong&gt;，只转面板的话面板能开、客户端连不上网关：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh -N -L 3066:127.0.0.1:3066 -L 3065:127.0.0.1:3065 root@&amp;lt;你的服务器IP&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 端口改成你自己的。这条命令要一直开着；它不输出任何东西、看着像卡住 —— 那是在转发，正常&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;想再开回来：重跑加 &lt;code&gt;--open-register&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h2 id="不绑域名怎么用ssh-隧道"&gt;不绑域名怎么用（SSH 隧道）&#10;&lt;/h2&gt;&lt;p&gt;不绑域名完全可行，但有个细节第一次写时漏了：&lt;strong&gt;隧道必须把网关端口一起转&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;只转面板（3066）的话，你能打开管理面板、能加账号、能建 Key——然后客户端连不上，因为客户端要连的是&lt;strong&gt;网关&lt;/strong&gt;（3065）。症状是&amp;quot;面板一切正常，但 API 就是不通&amp;quot;，很容易怀疑到别的地方去。&lt;/p&gt;&#10;&lt;p&gt;装完之后脚本会把这条命令按你的实际端口和 IP 打印出来，直接复制就行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ssh -N -L 3066:127.0.0.1:3066 -L 3065:127.0.0.1:3065 root@&amp;lt;你的服务器IP&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这条命令要一直开着（另开一个终端窗口跑）。它不输出任何东西、看着像卡住——那是在转发，正常。要停就 &lt;code&gt;Ctrl+C&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;如果报 &lt;code&gt;Permission denied&lt;/code&gt;：脚本给的是 &lt;code&gt;root@IP&lt;/code&gt;，可能绕过了你已经配好的 ssh 别名/密钥。把你平时登录它的那条 ssh 命令拿出来，在后面加上这两个转发参数即可。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;隧道只对你自己这台电脑有效，别人访问不到（这也是它比把端口直接暴露到公网安全的地方）。然后：面板 → 浏览器开 &lt;code&gt;http://127.0.0.1:3066&lt;/code&gt;；客户端 &lt;code&gt;base_url&lt;/code&gt; → &lt;code&gt;http://127.0.0.1:3065/v1&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;嫌麻烦就绑个域名：带 &lt;code&gt;--domain 你的域名&lt;/code&gt; 重跑，自动签 HTTPS 证书，之后就不用隧道了。&lt;/p&gt;&#10;&lt;h2 id="改了什么实测与用户反馈挖到的-9-个真问题"&gt;改了什么：实测与用户反馈挖到的 9 个真问题&#10;&lt;/h2&gt;&lt;p&gt;脚本不是一次写成的。下面每一条都是实测撞出来的，不是&amp;quot;理论上可能&amp;quot;。&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;端口校验会&amp;quot;假通过&amp;quot;，然后访问 502。&lt;/strong&gt; 原来只查宿主机 &lt;code&gt;ss&lt;/code&gt; 看端口有没有被占。实测发现：宿主端口被 docker-proxy 占着，但容器里根本没有进程在监听——校验通过，一访问就 502。现在改成从容器内部验证两个端口真的在服务。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;交互式菜单的选择，从来没生效过。&lt;/strong&gt; &lt;code&gt;choose()&lt;/code&gt; 把选项菜单用 &lt;code&gt;printf&lt;/code&gt; 打到了 stdout，而调用方是 &lt;code&gt;$(choose ...)&lt;/code&gt;——菜单文本被一起捕获，&lt;code&gt;case&lt;/code&gt; 永远匹配不上，而且一个错都不报。原因很尴尬：所有手工测试都显式传了参数，从没走过交互分支。现在提示与菜单一律写 stderr，stdout 只留结果。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;--expose&lt;/code&gt; 拼错一个字母，会静默生成一个空路由。&lt;/strong&gt; &lt;code&gt;--expose foo&lt;/code&gt; 原样传下去，生成的站点块里没有任何 &lt;code&gt;handle&lt;/code&gt;，域名整体不通——而 Caddy 的 &lt;code&gt;validate&lt;/code&gt; 还能通过。现在枚举校验拦下来。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;--yes&lt;/code&gt; 重跑一次，域名和端口就丢了。&lt;/strong&gt; 状态文件没被当默认值用，重跑时回落到默认值；而磁盘上的反代块还指着旧端口——静默得到一个 502 的域名。现在改成状态文件提供默认值、命令行显式项优先；确实想去掉域名就显式 &lt;code&gt;--no-domain&lt;/code&gt;。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;改 Caddyfile 的过程中被打断，会留下半截配置。&lt;/strong&gt; 这种配置当下不发作（运行中的 Caddy 还用着旧配置），等下次 reload 或重启才炸，是最难查的那类故障。现在注册了信号处理，收到 SIGTERM 就把备份还原回去并重载。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;裸机装不了。&lt;/strong&gt; 原来要求机器上已有 Caddy，而实际上很多机器 80/443 上什么都没有。现在多了一种形态：自己起一个 &lt;code&gt;caddy:2-alpine&lt;/code&gt; 容器，配置和证书都放在安装目录里，跟别人的反代完全隔离。这里也踩过一个：bind mount 一个还不存在的文件，docker 会创建同名&amp;quot;目录&amp;quot;，于是 Caddy 起不来且报错极难看懂——所以必须先把配置文件落盘，再 &lt;code&gt;compose up&lt;/code&gt;。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;交互问得太多了。&lt;/strong&gt; 最初默认路径要回答 9 个问题。其中一半小白根本不该被问——端口是自动挑空闲的、时区默认就行、容器名更是无所谓。现在默认路径&lt;strong&gt;只问 2 个&lt;/strong&gt;：先问域名（它决定你后面怎么访问，是最关键的决策），再问一句&amp;quot;高级选项需要改吗&amp;quot;，默认 &lt;code&gt;n&lt;/code&gt; 就直接开装。命令行上给过 &lt;code&gt;--dir&lt;/code&gt;/&lt;code&gt;--mem&lt;/code&gt; 这类参数的话，脚本认为你是老手，第 2 步不问了，但仍会把没给的那几项问一遍。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;不绑域名时，SSH 隧道漏了网关端口。&lt;/strong&gt; 见上一节。现在两个端口一起转，而且脚本会按你的实际端口和公网 IP 把整条命令打印出来。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;把「封掉自助注册」设成默认，挡了正当用法。&lt;/strong&gt; 这条是用户直接反馈的：装完发现自助注册被 403 挡了，而他就是想在浏览器里直接注册。当时的理由很充分——域名进 CT 日志会被公开索引。但&lt;strong&gt;理由充分不等于应该替用户做这个决定&lt;/strong&gt;：对一个自用工具来说，「能注册」是刚需，「防抢注」是加分项。现在默认&lt;strong&gt;不封&lt;/strong&gt;，同时把安全提醒做在它该在的地方。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="值得单独记的两个坑"&gt;值得单独记的两个坑&#10;&lt;/h2&gt;&lt;h3 id="一键脚本不该让用户自己去装依赖"&gt;「一键脚本」不该让用户自己去装依赖&#10;&lt;/h3&gt;&lt;p&gt;用户在新机器上跑，撞到这句：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;× 这台机器上还没装 docker（跑这个服务必须用它）&#10; 装它很简单，把下面这行粘进去回车就行（官方一键脚本）：&#10; curl -fsSL https://get.docker.com | sh&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;他的回复很直接：「你必须要把我的一键脚本支持自动检测环境自动安装需要的依赖，而不是让用户自己去安装」。他说得对——&amp;ldquo;给你一条命令让你自己粘&amp;quot;根本不叫一键，叫&amp;quot;一键加一步&amp;rdquo;。&lt;/p&gt;&#10;&lt;p&gt;现在改成缺什么自己装，&lt;strong&gt;四种方式依次降级&lt;/strong&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;&#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;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;docker 官方脚本&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;2&lt;/td&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;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;发行版自带仓库（&lt;code&gt;apt install docker.io&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;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;重装包（&lt;code&gt;apt --reinstall&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;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;实测在一台被卸干净的 Debian 12 上：从&amp;quot;没有 docker&amp;quot;到 agent2api 装好可用，总共 60 秒。&lt;/p&gt;&#10;&lt;p&gt;判定标准也换了——&lt;code&gt;get.docker.com&lt;/code&gt; 会&lt;strong&gt;退出 0 却什么都没装&lt;/strong&gt;（当 docker 的包显示&amp;quot;已安装&amp;quot;、但二进制文件被删掉时，&lt;code&gt;apt install&lt;/code&gt; 认为&amp;quot;已是最新版&amp;quot;直接跳过）。所以必须换成「docker 命令是否真的可用」：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker_ok&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; command -v docker &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 每个方式跑完都验一次，而不是看它的退出码&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sh &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$script&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$log&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; 2&amp;gt;&amp;amp;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker_ok &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&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;check_docker&lt;/code&gt; 原来在命令分发之前就跑，所以 &lt;code&gt;--status&lt;/code&gt; / &lt;code&gt;--uninstall&lt;/code&gt; 也会触发自动安装——用户说&amp;quot;我要卸载&amp;quot;，脚本却给他装了个 docker 出来。现在只有&lt;strong&gt;安装和升级&lt;/strong&gt;才会自动装依赖。不想被动的话有 &lt;code&gt;--no-deps&lt;/code&gt;，缺什么只告诉你命令。&lt;/p&gt;&#10;&lt;h3 id="宿主机端口看起来被占了其实没占"&gt;宿主机端口&amp;quot;看起来被占了&amp;quot;，其实没占&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;docker run -p 127.0.0.1:3065:3065&lt;/code&gt; 之后，宿主机的 3065 端口会被 &lt;code&gt;docker-proxy&lt;/code&gt; 绑上——哪怕容器里的进程早就退出了、或者压根没监听这个端口。于是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ss -ltn &lt;span style="color:#75715e"&gt;# 看宿主机：3065 是&amp;#34;被占用&amp;#34;的&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl 127.0.0.1:3065 &lt;span style="color:#75715e"&gt;# 从容器外：502&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 从容器内 curl：Connection refused&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;docker exec &amp;lt;容器&amp;gt; curl -sf http://127.0.0.1:&amp;lt;端口&amp;gt;/&lt;/code&gt;，两个端口都过才算就绪。&lt;/p&gt;&#10;&lt;p&gt;同一类问题的另一半：&lt;strong&gt;改自定义端口时，光改宿主映射没用&lt;/strong&gt;。容器内部监听哪个端口，是由 &lt;code&gt;AGENT2API_PANEL_PORT&lt;/code&gt; / &lt;code&gt;AGENT2API_PROXY_PORT&lt;/code&gt; 两个环境变量决定的。只改 compose 的 &lt;code&gt;ports:&lt;/code&gt; 而不改环境变量，症状就是&amp;quot;面板能开、&lt;code&gt;/v1&lt;/code&gt; 一直 502&amp;quot;。&lt;/p&gt;&#10;&lt;h2 id="验证矩阵"&gt;验证矩阵&#10;&lt;/h2&gt;&lt;p&gt;脚本自带回归套件 &lt;code&gt;test-install-agent2api.sh&lt;/code&gt;，一条命令跑完 37 个用例，退出码就是失败数。最近一次在 Debian 12 + Docker 29.8.1 上：&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;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;10&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;3&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;状态与版本管理（status / check-update / 升级同版本 / 升级失败回滚）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&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;2&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;域名与 TLS（签证书、注册开关、托管块幂等、状态复用、冲突在动手前失败、&lt;code&gt;--no-domain&lt;/code&gt; 摘除）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&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;流式 SSE 未被反代缓冲&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&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;卸载（含&amp;quot;从未安装过&amp;quot;时也不报错）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&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;1&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;strong&gt;合计&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;37&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;37 / 37&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;流式那条判据不是&amp;quot;能返回内容&amp;quot;，而是&lt;strong&gt;首字节时间明显小于总耗时&lt;/strong&gt;。实测经 manager 网关首字节 0.58s、总耗时 3.28s，37 个 &lt;code&gt;data:&lt;/code&gt; 帧加一个 &lt;code&gt;[DONE]&lt;/code&gt;——说明是逐帧下发而不是整段缓冲。Caddy 默认就透传，但如果你前面挂的是 Nginx，&lt;strong&gt;必须显式 &lt;code&gt;proxy_buffering off&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;哪些没进自动套件，也说清楚&lt;/strong&gt;：裸机自建 Caddy 那套（需要腾出 80/443）、SIGTERM 中断还原（需要可控的中断时机）、&lt;code&gt;--with-manager&lt;/code&gt; 的端到端登记（会改动生产 manager 的上游列表）。这三项都是手工验证过的，但没做成自动化——所以别把&amp;quot;37/37 全绿&amp;quot;理解成&amp;quot;什么都验过了&amp;quot;。&lt;/p&gt;&#10;&lt;h3 id="那些静默型问题"&gt;那些&amp;quot;静默型&amp;quot;问题&#10;&lt;/h3&gt;&lt;p&gt;多轮压测抓到的 10 个真问题里，3 个是&amp;quot;静默型&amp;quot;，最值得记：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;--expose foo&lt;/code&gt; 不带域名时被静默吞掉（没域名时脚本把暴露模式强制设成 &lt;code&gt;none&lt;/code&gt;，非法值被无声覆盖）。枚举值对不对跟有没有域名无关，现在在解析参数时就拦。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--caddy-mode bogus&lt;/code&gt; 被静默忽略（内部 &lt;code&gt;case&lt;/code&gt; 匹配不上就沿用自动探测结果，用户明确指定的形态没生效也没有提示）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;在&amp;quot;确认开始安装&amp;quot;处输入中断（EOF）会直接开装&lt;/strong&gt;。&lt;code&gt;read&lt;/code&gt; 失败时原来写的是 &lt;code&gt;ans=&amp;quot;${ans:-$def}&amp;quot;&lt;/code&gt;，而这个问题的默认值正好是 &lt;code&gt;y&lt;/code&gt;——终端一断、或输入被别的东西耗尽，它就自己开装了。现在读不到输入就按&amp;quot;否&amp;quot;处理。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;还有一条不算静默但更严重：&lt;strong&gt;状态文件以前是 &lt;code&gt;source&lt;/code&gt; 执行的&lt;/strong&gt;，它能被写坏，也能被写进别的东西——而脚本以 root 运行。现在改成自己解析 + 键白名单 + &lt;code&gt;printf -v&lt;/code&gt; 赋值，&lt;strong&gt;绝不执行文件里的内容&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;其余 6 条包括：&lt;code&gt;--no-domain&lt;/code&gt; 与 &lt;code&gt;--domain&lt;/code&gt; 同时给会自相矛盾；&lt;code&gt;--mem 0m&lt;/code&gt; / &lt;code&gt;1k&lt;/code&gt; 被放行（docker 最低要 6m）；状态文件坏了会静默按默认值装；只传一个 &lt;code&gt;--dir&lt;/code&gt; 会被连问 6 个高级问题；重跑选&amp;quot;重新配置&amp;quot;时那个高级选项开关永不出现；Caddy 备份文件无限累积（现在只保留最近 3 份，且只删本脚本自己建的）。&lt;/p&gt;&#10;&lt;p&gt;每修一个，就补一条回归用例——套件从 29 涨到 36，不是为了数字好看，是为了这些 bug 不可能再回来。&lt;/p&gt;&#10;&lt;h2 id="常见报错都是真实遇到过的"&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;&#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;sudo: command not found&lt;/code&gt;，后面跟 &lt;code&gt;curl: (23) Failed writing body&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;你登录就是 root，而这台机器没装 sudo&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;去掉 &lt;code&gt;sudo&lt;/code&gt;，直接 &lt;code&gt;bash ~/a2a.sh&lt;/code&gt;。先看提示符是 &lt;code&gt;#&lt;/code&gt; 还是 &lt;code&gt;$&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;curl -fsSL … | bash&lt;/code&gt; 的失败是&lt;strong&gt;无声的&lt;/strong&gt;）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;换源（见下面三个源），或改用 &lt;code&gt;-o 文件 &amp;amp;&amp;amp; bash 文件&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;code&gt;docker: command not found&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;机器上还没装 Docker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;脚本会自动装；或用 &lt;code&gt;--no-deps&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;需要 root 权限运行…&lt;/td&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;bash&lt;/code&gt; 换成 &lt;code&gt;sudo bash&lt;/code&gt;（脚本会先看这台机器有没有 sudo，再给对应的建议）&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;80/443 被 xxx 占用&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;机器上已有反代（Nginx 等）在跑&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;脚本会打印可直接粘贴的 Nginx 片段；或腾出 80/443 后用 &lt;code&gt;--caddy-mode self&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;code&gt;setup&lt;/code&gt; 返回 403&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;这台装的时候用了 &lt;code&gt;--lock-register&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;重跑加 &lt;code&gt;--open-register&lt;/code&gt; 开回来；或按隧道方式注册&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="下载"&gt;下载&#10;&lt;/h2&gt;&lt;p&gt;取件码 20818 —— 永久有效、不限次数：&lt;a class="link" href="https://pan.ailxw.com/pickup/20818" target="_blank" rel="noopener"&#10; &gt;https://pan.ailxw.com/pickup/20818&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;三个下载源，哪个通用哪个（脚本内容完全一样，取回后可核对下面的 SHA256）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 源 1：网盘（推荐，国内可达）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -fsSL &lt;span style="color:#e6db74"&gt;&amp;#34;https://pan.ailxw.com/api/pickup-download?code=20818&amp;#34;&lt;/span&gt; -o ~/a2a.sh &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo bash ~/a2a.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 源 2：jsDelivr CDN&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -fsSL &lt;span style="color:#e6db74"&gt;&amp;#34;https://cdn.jsdelivr.net/gh/yys9253462-gif/agent2api-installer@main/install-agent2api.sh&amp;#34;&lt;/span&gt; -o ~/a2a.sh &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo bash ~/a2a.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 源 3：GitHub 直连&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -fsSL &lt;span style="color:#e6db74"&gt;&amp;#34;https://raw.githubusercontent.com/yys9253462-gif/agent2api-installer/main/install-agent2api.sh&amp;#34;&lt;/span&gt; -o ~/a2a.sh &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo bash ~/a2a.sh&#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" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -fsSL https://cdn.jsdelivr.net/gh/yys9253462-gif/agent2api-installer@main/deploy.sh | sudo bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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;&lt;code&gt;install-agent2api.sh&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;95874 字节&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;SHA256&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;8131f3301acbc81315625e428e37371b4bfd81b97544d7d3bdb41765b56dedf7&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;v1.7.0&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;只要 docker（Debian/Ubuntu 系实测；脚本自身无其它依赖）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 下载后建议先核一下 SHA256 再跑&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sha256sum install-agent2api.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;源码与回归套件：&lt;a class="link" href="https://github.com/yys9253462-gif/agent2api-installer" target="_blank" rel="noopener"&#10; &gt;https://github.com/yys9253462-gif/agent2api-installer&lt;/a&gt;，欢迎提 issue。&lt;/p&gt;&#10;</description></item></channel></rss>