agent2api 一键安装器:一条命令装起带 HTTPS 的本地 AI 网关

一条命令把 agent2api 装到服务器上:自动挑空闲端口、自动签 HTTPS 证书、自动认已有 Caddy、缺 docker 自己装。默认只问 2 个问题、中文回答也认、报错都给可粘的命令。附五轮压测与 37 项回归验证。

一句话

把 agent2api 装到你的服务器上,一条命令。它是本地网关——把 WorkBuddy、Qoder、Cline 这类客户端的登录态转成 OpenAI 兼容接口,自己管多账号、模型路由和出网。脚本会自动挑空闲端口、想绑域名就自动申请 Let's Encrypt 证书、自动认你机器上已有的 Caddy 并接好反代。

# 在 VPS 上粘这一行就装完了 —— 不用先在本地下载再 scp 上传
curl -fsSL "https://pan.ailxw.com/api/pickup-download?code=20818" -o ~/a2a.sh && bash ~/a2a.sh
提示符是 #(登录就是 root,多数 VPS 默认如此)就用上面这条;是 $(普通用户)就把最后的 bash 换成 sudo bash。
别习惯性加 sudo —— 很多精简镜像根本没装 sudo,加了会报 sudo: command not found,后面还跟一个
curl: (23) Failed writing body,看着像网络问题,其实是 sudo 不存在。
它只动三处:起一个 docker 容器、往 Caddyfile 里加一段带标记的站点块(--no-domain 可一键摘掉)、在安装目录写几个文件。改反代配置前先备份、改完先校验、失败自动回滚;原有站点全程不受影响。
注意是在 VPS 上执行,不是在你自己的电脑上。粘上去如果没反应,说明这个下载源不通,文末「下载」一节有两个备用源。

装完之后会得到什么

项目说明
面板https://你的域名/(不绑域名时走 SSH 隧道,见下文「不绑域名怎么用」)
网关https://你的域名/v1,客户端 base_url 填它(不绑域名时是 http://127.0.0.1:<网关端口>/v1)
证书Let's Encrypt 自动签发 + 自动续期(Caddy 负责)
容器单容器 + 可选一个自建 Caddy 容器;内存上限默认 384m
数据全在安装目录(data/),删目录即彻底清理

命令行

最常用的四条:

命令干什么
sudo bash install-agent2api.sh交互式安装(第一次用这个)
sudo bash install-agent2api.sh --dry-run只打印它打算做什么,不动手
sudo bash install-agent2api.sh --yes --domain a2a.example.com全自动 + 绑域名签证书
sudo bash install-agent2api.sh --uninstall卸载(停容器 + 摘掉站点块)

装完之后的运维:

命令干什么
--status容器/端口健康、域名可达、证书到期、日志尾
--check-update查 Docker Hub 上有没有新版本
--upgrade升级;健康复检不过自动回滚

域名与反代相关:

参数说明
--domain <域名>绑域名 + 签证书;不带则沿用上次的
--no-domain明确不要域名,移除上次写入的站点块
`--expose both\panel\gateway`域名下暴露什么(默认 both,/v1* 走网关其余走面板)
`--caddy-mode host\docker\self`强制反代形态;默认自动探测
`--cf y\n`域名是否走 Cloudflare 橙云(自动加真实 IP 还原)

其它:--dir 安装目录、--tag 镜像版本、--panel-port / --gateway-port 指定端口、--mem 内存上限、--lock-register / --open-register 注册开关、--with-manager 登记为 workbuddy-manager 的上游。

关于升级,有个坑值得先说:agent2api 面板里那个「立即更新」按钮在 Docker 部署下是用不了的——它去 GitHub Releases 下载,而那个仓库的 Releases 里只有桌面端安装包(.dmg 和 setup.exe),没有任何 Linux 产物。面板自己也会提示「请通过 Docker 镜像更新」。所以升级只能换镜像,--upgrade 干的就是这件事:改 compose 里的镜像 tag → 拉取 → 重建 → 等 healthy → 从容器内部复核两个端口,任何一步不过就自动回滚旧版本并把状态文件也一起还原。

改了什么(实测 + 用户反馈挖到的 9 个真问题)

脚本不是一次写成的。下面每一条都是实测撞出来的,不是"理论上可能"。

1. 端口校验会"假通过",然后访问 502。 原来只查宿主机 ss 看端口有没有被占。实测发现:宿主端口被 docker-proxy 占着,但容器里根本没有进程在监听——校验通过,一访问就 502。现在改成从容器内部验证两个端口真的在服务。

2. 交互式菜单的选择,从来没生效过。 choose() 函数把选项菜单用 printf 打到了 stdout,而调用方是 $(choose ...)——菜单文本被一起捕获,case 永远匹配不上,而且一个错都不报。它潜伏了很久,原因很尴尬:我所有手工测试都显式传了参数,从没走过交互分支。现在提示与菜单一律写 stderr,stdout 只留结果。

3. --expose 拼错一个字母,会静默生成一个空路由。 --expose foo 原样传下去,生成的站点块里没有任何 handle,域名整体不通——而 Caddy 的 validate 还能通过。现在枚举校验拦下来。

4. --yes 重跑一次,域名和端口就丢了。 状态文件没被当默认值用,重跑时回落到默认值;而磁盘上的反代块还指着旧端口——静默得到一个 502 的域名。现在改成状态文件提供默认值、命令行显式项优先;确实想去掉域名就显式 --no-domain,它会把站点块一起摘掉。

5. 改 Caddyfile 的过程中被打断,会留下半截配置。 这种配置当下不发作(运行中的 Caddy 还用着旧配置),等下次 reload 或重启才炸,是最难查的那类故障。现在注册了信号处理,收到 SIGTERM 就把备份还原回去并重载。

6. 裸机装不了。 原来要求机器上已有 Caddy,而实际上很多机器 80/443 上什么都没有。现在多了一种形态:自己起一个 caddy:2-alpine 容器,配置和证书都放在安装目录里,跟别人的反代完全隔离。实测在干净机器上从零到签出证书是全通的。这里也踩过一个:bind mount 一个还不存在的文件,docker 会创建同名"目录",于是 Caddy 起不来且报错极难看懂——所以必须先把配置文件落盘,再 compose up。

7. 交互问得太多了。 最初默认路径要回答 9 个问题:容器名、时区、镜像版本、面板端口、网关端口、内存上限、域名、要不要登记 manager、确认安装。其中一半小白根本不该被问 —— 端口是自动挑空闲的、时区默认就行、容器名更是无所谓。现在的默认路径只问 2 个:先问域名(它决定你后面怎么访问,是最关键的决策,所以放最前),再问一句"高级选项需要改吗",默认 n 就直接开装。命令行上给过 --dir/--mem 这类参数的话,脚本认为你是老手,第 2 步不问了,但仍会把没给的那几项问一遍。

8. 不绑域名时,SSH 隧道漏了网关端口。 原来只让你转发面板端口(ssh -N -L 3066:...)。你能打开面板、能加账号、能建 Key —— 然后客户端连不上。因为客户端要连的是网关(3065),而隧道里根本没有它。症状是"面板一切正常但 API 就是不通",会让人往别处怀疑很久。现在两个端口一起转,而且脚本会按你的实际端口和公网 IP 把整条命令打印出来,直接复制即可(原来写的是 <本机> 占位符,还配一句"base_url = 上面的网关地址"——上面压根没有网关地址)。

9. 我把「封掉自助注册」设成了默认,挡了正当用法。 这条是用户直接反馈的:装完发现自助注册被 403 挡了,而他就是想在浏览器里直接注册。 我当时的理由很充分 —— 域名进 CT 日志会被公开索引,不封等于把管理台交给陌生人。 但理由充分不等于应该替用户做这个决定:对一个自用工具来说,「能注册」是刚需,「防抢注」是加分项, 我把优先级搞反了。现在默认不封,注册端点正常可用;同时把安全提醒做在它该在的地方 —— 装完检测管理员注册了没,没注册就醒目提醒「现在任何人打开面板都能抢注,请立刻去注册」。 想封的仍然可以 --lock-register,两条路都留着了。

再 5 轮:这次按"用户实际怎么操作"来跑

前几轮我都是按功能/入口测的(--uninstall 通不通、--domain 对不对)。这一轮换成按真实操作路径跑, 结果又抓到 5 个问题 —— 而且都是"按功能测永远测不出来"的那类。

轮次模拟的真实场景抓到
1全新 VPS 的第一天:一行命令装 → 只按回车 → 照它打印的提示操作 → 调通 API提示里"加上游账号"太笼统(小白不知道指什么)
2糊涂用户:全选 y、域名带 https:// 和斜杠、答非所问、菜单输 9中文回答「是/好/对」被当成"否";听不懂的回答默默当否;菜单越界静默回落
3中途放弃:下载阶段 Ctrl+C / kill -9,然后重跑中断提示说"配置已还原",但容器其实已经建了;中断后 --status 报"用 --dir 指定安装目录"(用户明明指定了)
4反复折腾:连跑 5 次、来回改端口/内存/域名Caddy 备份文件无限累积(连跑 4 次 = 4 个,堆在 /etc/caddy/)
5卸载重装:卸载(留目录)→ 重装 → 数据还在吗数据保留完全正确(注册和 Key 都在)✓

最严重的是第 2 轮那个:脚本是中文界面,但 ask_yn 只认英文 y/yes。 用户看到「要不要禁止别人从网上自己注册账号?」回答「是」—— 落进 *) 分支被当成否, 也就是执行了和他意思相反的操作。现在中文回答全部识别(是/好/对/要/嗯), 而且听不懂的回答会重问并解释,不再默默选一个。

第 3 轮那条也值得记:中断时我原本打印"配置已还原到你运行前的状态,没有改坏任何东西"—— 听起来很安心,但实测容器其实已经建起来了(只是状态文件还没写)。说"什么都没发生"是不诚实的, 用户会以为环境是干净的。现在会如实说明"容器可能已经建起来了,重跑一次就能接上"。

第 4 轮的备份累积是"用的越久越脏"那类问题:每次改共享反代配置都会存一份备份, 用户来回折腾几次就在 /etc/caddy/ 堆一排。现在只保留最近 3 份 —— 而且只删本脚本自己建的(严格匹配文件名模式,绝不碰用户自己的备份,实测验证过)。

第 1 轮还顺手补了一个信息:脚本原来只说"在「账号」里加上游账号",小白根本不知道指什么。 我扒了面板接口,实际支持 14 种(WorkBuddy / 小浣熊 / Qoder / Trae / Cline / Accio / ZCode / CatPaw / CodeArts…), 现在直接列在提示里。

被用户骂醒的一次:「一键脚本」不该让用户自己去装依赖

用户在新机器上跑,撞到这句:

× 这台机器上还没装 docker(跑这个服务必须用它)
装它很简单,把下面这行粘进去回车就行(官方一键脚本):
      curl -fsSL https://get.docker.com | sh
装完再重新跑本脚本即可。

他的回复很直接:「你必须要把我的一键脚本支持自动检测环境自动安装需要的依赖,而不是让用户自己去安装」。

他说得对。"给你一条命令让你自己粘"根本不叫一键。 叫"一键加一步"。凡是这种"你缺 X,去装一下 X 再回来"的设计,都是把麻烦推给用户。

现在改成:缺什么自己装,四种方式依次降级——

方式做什么什么时候能救
1docker 官方脚本正常情况,最快
2官方脚本 + 阿里云镜像国内直连官方源慢/不通
3发行版自带仓库(apt install docker.io)官方源整体不可达
4重装包(apt --reinstall)包显示已装、二进制却缺失/损坏

实测在一台被卸干净的 Debian 12 上:从"没有 docker"到 agent2api 装好可用,总共 60 秒。

这里踩到一个值得记的坑:我最初用"脚本退出码"判断装成功没装成功。结果实测发现 —— get.docker.com 会退出 0 却什么都没装:当 docker 的包显示"已安装"、但二进制文件被删掉时, apt install 认为"已是最新版"直接跳过,脚本照样报成功。

所以判定标准必须换成「docker 命令是否真的可用」:

docker_ok() { command -v docker >/dev/null 2>&1; }
# 每个方式跑完都验一次,而不是看它的退出码
sh "$script" >"$log" 2>&1 || true
docker_ok && ok=1

这条修正本身就是"方式 4"存在的原因 —— 如果我只信退出码,就永远不会走到重装那一步, 用户会卡在一个"脚本说装好了、但 docker 根本不在"的状态里。

还顺手修了一个反直觉的行为:check_docker 在命令分发之前就跑,所以 --status / --uninstall 也会触发自动安装 —— 用户说"我要卸载",脚本却给他装了个 docker 出来。(这是我测试时踩到的: 我的一条测试命令里先跑 --uninstall,结果它把 docker 装回来了,害我排查了半天。) 现在只有安装和升级才会自动装依赖。

另外给不想被动的用户留了后门:--no-deps —— 不碰你的系统,缺什么只告诉你命令。

一个值得记的坑:宿主机端口"看起来被占了",其实没占

这是第 1 条的完整版,也是我认为最值得单独讲的一条。

docker run -p 127.0.0.1:3065:3065 之后,宿主机的 3065 端口会被 docker-proxy 绑上——哪怕容器里的进程早就退出了、或者压根没监听这个端口。于是:

  • ss -ltn 看宿主机:3065 是"被占用"的
  • 从容器外 curl 127.0.0.1:3065:502
  • 从容器内 curl 127.0.0.1:3065:Connection refused

只查宿主端口的校验,在这件事上是不可信的。 判断"服务真的起来了没",必须进容器里去看,或者从外部发一个真实请求看响应码。脚本现在的自检是后者:docker exec <容器> curl -sf http://127.0.0.1:<端口>/,两个端口都过才算就绪。

同一类问题的另一半是:改自定义端口时,光改宿主映射没用。agent2api 容器内部监听哪个端口,是由 AGENT2API_PANEL_PORT / AGENT2API_PROXY_PORT 两个环境变量决定的。只改 compose 的 ports: 而不改环境变量,症状就是"面板能开、/v1 一直 502"。

验证矩阵

脚本自带一个回归套件 test-install-agent2api.sh,一条命令跑完 37 个用例,退出码就是失败数。最近一次在 Debian 12 + Docker 29.8.1 上:

分组用例数结果
参数校验(端口非数字/越界、枚举拼错、路径、内存格式、容器名)10全过
默认值路径与幂等(无域名安装、重跑不漂移、不传域名不该有域名)3全过
状态与版本管理(status / check-update / 升级同版本 / 升级失败回滚)4全过
端口被占自动换端口、容器名冲突定向报错2全过
域名与 TLS(签证书、注册开关 lock/open、托管块幂等、状态复用、冲突在动手前失败、--no-domain 摘除)6全过
流式 SSE 未被反代缓冲1全过
卸载(含"从未安装过"时也不报错)2全过
原有生产站点未被影响1全过
合计3737 / 37

流式那条值得单独说:判据不是"能返回内容",而是首字节时间明显小于总耗时。实测经 manager 网关首字节 0.58s、总耗时 3.28s,37 个 data: 帧加一个 [DONE]——说明是逐帧下发而不是整段缓冲。Caddy 默认就透传,但如果你前面挂的是 Nginx,必须显式 proxy_buffering off,否则首字延迟会等于整段生成时间。脚本给 Nginx 用户打印的配置片段里带了这行。

哪些没进自动套件,也说清楚:裸机自建 Caddy 那套(需要腾出 80/443,在有反代的机器上跑会打断现有服务)、SIGTERM 中断还原(需要可控的中断时机)、--with-manager 的端到端登记(会改动生产 manager 的上游列表)。这三项都是手工验证过的,但没做成自动化——所以别把"37/37 全绿"理解成"什么都验过了"。

又跑了 5 轮专项压测(奔着找 bug 去,不是走一遍)

轮次打法结果
1完整回归套件(域名 + 证书 + 真实流式)29 / 29
2交互流程(pty 驱动:默认两回车、高级选项、绑域名全链、已安装菜单、非法输入、Ctrl+C 中断)抓 3 个
3边界与异常(参数冲突、越界值、docker 缺失、状态文件损坏、端口占满)抓 6 个
4真实使用场景(装 → 真的走 API 注册管理员 → 建 Key → 调 /v1/models → 升级 → 回滚 → 卸载)全通
5输出可读性与文档一致性抓 1 个

10 个真问题里,3 个是"静默型"—— 我认为这一类最值得记:

1. --expose foo 不带域名时被静默吞掉。 没域名时脚本会把暴露模式强制设成 none,于是这个非法值被无声覆盖,一个错都不报。枚举值对不对,跟有没有域名无关 —— 现在在解析参数时就拦。 2. --caddy-mode bogus 被静默忽略。 内部是个 case 匹配,匹配不上就沿用自动探测结果。用户明确指定的形态没生效,也没有任何提示。 3. 在"确认开始安装"处输入中断(EOF)会直接开装。 read 失败时我原来写的是 ans="${ans:-$def}",而这个问题的默认值正好是 y。也就是说终端一断、或者输入被别的东西耗尽,它就自己开装了。现在读不到输入就按"否"处理,并明确说一句。

还有一条不算静默、但更严重:状态文件以前是 source 执行的。它能被写坏,也能被写进别的东西 —— 而脚本以 root 运行。现在改成自己解析 + 键白名单 + printf -v 赋值,绝不执行文件里的内容。

其余 6 条:--no-domain 与 --domain 同时给会自相矛盾(既设了域名又按不绑域名处理);--mem 0m / 1k 被放行(docker 必然启动失败,它最低要 6m);状态文件坏了会静默按默认值装(可能装了另一个容器);只传一个 --dir 会被连问 6 个高级问题;重跑选"重新配置"时那个高级选项开关永不出现。

每修一个,我就补一条回归用例。 套件从 29 涨到 34 —— 不是为了数字好看,是为了这些 bug 不可能再回来。

又跑了 5 轮:这次专门盯"新手能不能自己走通"

前一轮是找 bug,这一轮的标准换成了"一个不懂技术的人,能不能只靠脚本自己打印的东西走通"。又抓到 6 个问题:

轮次打法发现
1首屏审计(用新手眼睛看第一屏)开头没说"在装什么、要多久";术语密集(宿主 Caddy / systemd / 反代后端);下载那步没给预期;--yes 还打印提问说明,看着像要问其实没问
2逐句文案审计11 处术语/黑话("镜像 tag"→"版本"、"容器名"→"服务名字"、"上游"→"接到那个面板上")
3异常场景引导docker 缺失只说"请先安装 Docker" —— 新手根本不知道怎么做
4完成后「下一步」引导漏了最关键的一步:没说要"加上游账号" —— 少了这步客户端拿不到任何模型
5只靠脚本输出走通脚本打印的隧道命令会绕过你已有的 ssh 别名/密钥,报 Permission denied

第 5 条是我自己踩的:我照着脚本打印的命令执行,被拒了 —— 因为脚本给的是 root@IP,而服务器上我平时是用 ssh se(配了密钥)登录的。它绕过了我已经配好的东西。 现在会补一句:"如果报 Permission denied,就把你平时登录它的那条 ssh 命令拿出来,在后面加上这两个转发参数。"

还抓到一个隐蔽的源码 bug:printf 的格式符比参数少一个时,printf 会重复整个格式串 —— 输出里"第 2 步:另开浏览器,打开 " 打了两遍、第二遍地址是空的。修完顺手写了个扫描脚本,把全项目 4 个 shell 文件都过了一遍(现在 0 处)。

改动就一句话:把用户当成不懂技术的人。 开头先说人话;术语换成人话;报错一律给能直接粘的命令;装完只强调一件事,技术细节降级到后面;补上"进面板后按顺序做三件事"。

上线后被用户抓到一个 bug:选「卸载」却继续安装

用户报的:重跑脚本时会先弹一个菜单(重新配置 / 升级 / 卸载 / 退出),他选了「3) 卸载」,脚本却继续往下走,还问他"确认开始安装?"。

原因很典型:菜单里选「卸载」只是把 DO_UNINSTALL=1,而那个标记是在 main() 开头就检查过的 —— 现在再设等于没人看。"设个标记让别处去处理"这种间接写法,一定要确认"处理方"还没跑过。

修法就是别绕这一圈:菜单里直接调用 do_uninstall / do_upgrade。顺带把全部同类标记(DO_STATUS/DO_UPGRADE/DO_CHECK_UPDATE)审了一遍,确认只有这一处。

更值得说的是我为什么没测出来:我测了 --uninstall 和 --upgrade 两个命令行入口,就默认"菜单选 3 等于 --uninstall"——没测。 这属于典型的"看起来等价所以跳过"。现在补了 2 个用 script(1) 造 pty 驱动菜单的用例,套件从 34 涨到 36。

跑一次看看

# 1. 在 VPS 上一行装完(推荐;不用先在本地下载再上传)
#    提示符是 # 用这条;是 $ 就把最后的 bash 换成 sudo bash
curl -fsSL "https://pan.ailxw.com/api/pickup-download?code=20818" -o ~/a2a.sh && bash ~/a2a.sh

# 2. 想带参数就接在后面
curl -fsSL "https://pan.ailxw.com/api/pickup-download?code=20818" -o ~/a2a.sh \
  && bash ~/a2a.sh --domain a2a.example.com --expose both

# 3. 脚本已经在机器上了,就直接跑(全交互,推荐第一次)
sudo bash install-agent2api.sh

# 4. 想先看清楚它要干什么
sudo bash install-agent2api.sh --dry-run

# 5. 装完看状态
sudo bash install-agent2api.sh --status --dir /opt/agent2api

# 6. 以后升级(面板里的"立即更新"在 Docker 部署下用不了,用这个)
sudo bash install-agent2api.sh --check-update --dir /opt/agent2api
sudo bash install-agent2api.sh --upgrade      --dir /opt/agent2api

# 7. 不想要了
sudo bash install-agent2api.sh --uninstall

为什么写成 -o 文件 && bash 文件,而不是顺手就来的 curl … | bash —— 这两种写法我都试过,各有一个坑,而且都是"看起来在跑、其实没跑对":

坑一:管道会把 stdin 占掉。 安装器默认是交互式的,curl | bash 时它读不到你的键盘。我第一次在测试机上验证时就撞上了:bash install.sh < /dev/null 跑出来,它一个都不问、静默全部采用默认值往下装 —— 你以为在交互,其实配置项你一个都没选过。

坑二:管道失败是无声的。 curl -fsSL … | bash 里如果源不通,-f 让 curl 不输出错误体、-s 让它不输出进度,于是 curl 什么都不打印、bash 收到空输入,你屏幕上什么都不会出现。国内访问 cdn.jsdelivr.net 经常不通,症状就是"粘上去没反应"——我就是这么收到的反馈。

改成 -o 文件 && bash 文件:出错会打印原因、&& 会拦住后续、stdin 还是你的终端,交互正常。

(顺带说个细节:即使管道那两种坑都绕开,curl … | bash 还有个副作用 —— $0 会变成 bash。实测 echo 'echo $0' | bash 输出 bash,存成文件执行输出的才是文件路径。安装器要用自身路径打印"以后怎么重跑 / 怎么卸载",管道执行会让它打出 bash bash --uninstall 这种没法用的东西。所以仓库里的引导脚本 deploy.sh 也是先落盘再执行,并且在管道场景下把 stdin 接回终端。)

首次使用:打开面板注册管理员 → 「账号」里加上游账号 → 「网关 Key」建一把 Key → 客户端 base_url 填 https://你的域名/v1、api_key 填那把 Key。

自助注册默认是开着的 —— 直接在浏览器里打开面板就能注册,不用绕隧道。

但这里有个必须知道的背景:agent2api 的规则是「第一个打开面板的人注册成管理员」,而域名签了证书就会进 Certificate Transparency 日志、被公开索引。也就是说,从面板上线到你注册完成之间,谁先打开谁就是管理员。所以脚本装完会检测管理员注册了没,没注册就醒目提醒:

× 管理员还没注册 —— 现在任何人打开面板都能抢注成管理员,请立刻去注册!
    立刻打开:https://你的域名/

看到这行就去注册,注册完再干别的。想更稳妥就封掉:重跑加 --lock-register,注册端点返回 403,注册改走 SSH 隧道(隧道直连容器、不经过 Caddy,不受该规则影响)。注意两个端口都要转发,只转面板的话面板能开、客户端连不上网关:

ssh -N -L 3066:127.0.0.1:3066 -L 3065:127.0.0.1:3065 root@<你的服务器IP>
# 端口改成你自己的。这条命令要一直开着;它不输出任何东西、看着像卡住 —— 那是在转发,正常

想再开回来:重跑加 --open-register。

不绑域名怎么用(SSH 隧道)

不绑域名是完全可行的,但有个细节第一次写时我漏了:隧道必须把网关端口一起转。

只转面板(3066)的话,你能打开管理面板、能加账号、能建 Key —— 然后客户端连不上,因为客户端要连的是网关(3065)。症状是"面板一切正常,但 API 就是不通",很容易怀疑到别的地方去。

装完之后脚本会把这条命令按你的实际端口和 IP 打印出来,直接复制就行:

ssh -N -L 3066:127.0.0.1:3066 -L 3065:127.0.0.1:3065 root@<你的服务器IP>
  • 这条命令要一直开着(另开一个终端窗口跑)。它不输出任何东西、看着像卡住 —— 那是在转发,正常。要停就 Ctrl+C。
  • 隧道只对你自己这台电脑有效,别人访问不到(这也是它比把端口直接暴露到公网安全的地方)。
  • 然后:面板 → 浏览器开 http://127.0.0.1:3066;客户端 base_url → http://127.0.0.1:3065/v1。

嫌麻烦就绑个域名:带 --domain 你的域名 重跑,自动签 HTTPS 证书,之后就不用隧道了。

常见报错(都是真实遇到过的)

你看到的真正的原因怎么办
sudo: command not found,后面跟 curl: (23) Failed writing body你登录就是 root,而这台机器没装 sudo去掉 sudo,直接 bash ~/a2a.sh。先看提示符是 # 还是 $
粘上去一点输出都没有,光标直接回来下载源不通(`curl -fsSL … \bash` 的失败是无声的)换源(见下面三个源),或改用 -o 文件 && bash 文件
docker: command not found机器上还没装 Docker先装:`curl -fsSL https://get.docker.com \sh`
需要 root 权限运行…你是普通用户按提示把 bash 换成 sudo bash(脚本会先看这台机器有没有 sudo,再给对应的建议)
80/443 被 xxx 占用机器上已有反代(Nginx 等)在跑脚本会打印可直接粘贴的 Nginx 片段;或腾出 80/443 后用 --caddy-mode self
打开面板提示注册被拒 / setup 返回 403这台装的时候用了 --lock-register重跑加 --open-register 开回来;或按隧道方式注册

下载

取件码 20818 —— 永久有效、不限次数:

https://pan.ailxw.com/pickup/20818

三个下载源,哪个通用哪个(脚本内容完全一样,取回后可核对下面的 SHA256):

# 源 1:网盘(推荐,国内可达)
curl -fsSL "https://pan.ailxw.com/api/pickup-download?code=20818" -o ~/a2a.sh && sudo bash ~/a2a.sh

# 源 2:jsDelivr CDN
curl -fsSL "https://cdn.jsdelivr.net/gh/yys9253462-gif/agent2api-installer@main/install-agent2api.sh" -o ~/a2a.sh && sudo bash ~/a2a.sh

# 源 3:GitHub 直连
curl -fsSL "https://raw.githubusercontent.com/yys9253462-gif/agent2api-installer/main/install-agent2api.sh" -o ~/a2a.sh && sudo bash ~/a2a.sh

也可以让引导脚本自己挨个试(它会依次尝试上面三个源,落盘后执行):

curl -fsSL https://cdn.jsdelivr.net/gh/yys9253462-gif/agent2api-installer@main/deploy.sh | sudo bash
项目值
文件名install-agent2api.sh
大小95874 字节
SHA2568131f3301acbc81315625e428e37371b4bfd81b97544d7d3bdb41765b56dedf7
版本v1.7.0
依赖只要 docker(Debian/Ubuntu 系实测;脚本自身无其它依赖)

源码与回归套件在这里,欢迎提 issue:

https://github.com/yys9253462-gif/agent2api-installer

# 下载后建议先核一下 SHA256 再跑
sha256sum install-agent2api.sh
⚡ 极客核心要点提炼 可供 AI 智能体与搜索引擎引用检索

本文主题:agent2api 一键安装器:一条命令装起带 HTTPS 的本地 AI 网关

技术摘要:一条命令把 agent2api 装到服务器上:自动挑空闲端口、自动签 HTTPS 证书、自动认已有 Caddy、缺 docker 自己装。默认只问 2 个问题、中文回答也认、报错都给可粘的命令。附五轮压测与 37 项回归验证。

引用出处:https://isoziyuan.com/p/100171/(作者:Isoziyuan · 发布于爱搜资源网)