手把手:用 agent-template.sh 做模板、开新 agent、连接 T3 Code
一个脚本覆盖 agent 虚拟机的整个生命周期:在模板源机器上 install,做模板前 cleanup,每台克隆机 init,随时 check。本页按实际操作顺序,从下载脚本一直写到用浏览器、Mac App、手机连接 T3 Code。
四个子命令和整体流程
| 命令 | 在哪台机器上 | 做什么 |
|---|---|---|
install | 模板源(agent-01) | 全局代理 + 纽约时区;基础工具(git、gh、tmux、mosh、libatomic1、qemu-guest-agent…);Node 24 + pnpm;Docker(daemon 和容器内部都走代理);Claude Code、Codex CLI、OpenCode、T3 Code 命令行(只安装,不登录);PATH、tmux 配置、linger。可重复执行 |
check | 任何一台 | 检查时区、时间、IP、代理、工具、机器身份、T3 后台服务,每项 ✓ / ✗,✗ 会提示修复命令 |
cleanup | 要转成模板的那台(9000) | 删除登录凭证(Claude、Codex、OpenCode、GitHub、T3、SSH 私钥),卸载 T3 后台服务,清空 SSH 主机密钥和 machine-id,清理缓存,最后关机 |
init 主机名 | 每台克隆出来的新机器 | 改主机名、确认机器身份、Git 身份;逐项询问登录 Claude / Codex / OpenCode / GitHub;安装 T3 后台服务(自动配置 PATH 和局域网监听);可选 T3 Connect |
agent-01(快照 proxy_ok:系统 + 代理) │ ① 下载脚本 → install → 重新登录 → check │ ② 准备:Mac 公钥、Claude 通用配置、公开仓库(都不登录) │ ③ 拍快照 dev_tools │ │ 从 dev_tools 完整克隆 ▼ 9000 tpl-agent ── ④ cleanup(agent-01 先关机)→ 转换成模板 │ │ 完整克隆 ▼ agent-02、03 … ── ⑤ init agent-0N → 重新登录 → check → ⑥ 连接 T3 Code
dev 执行,不要用 root 或 sudo bash;需要权限的地方脚本会自己调用 sudo,用 root 执行会直接提示并退出。第一步:下载脚本
SSH 登录 agent 虚拟机后执行(后面的 ?t=… 是为了避免拿到缓存里的旧版本,更新脚本时也用这条):
curl -fsSL "https://pages.chenos.dev/workstation/scripts/agent-template.sh?t=$(date +%s)" -o ~/agent-template.sh bash ~/agent-template.sh # 不带参数:显示用法,确认下载的是完整的新版
想先看内容:less ~/agent-template.sh(按 q 退出)。
nano ~/agent-template.sh 粘贴保存。第二步:install(模板源机器)
想从干净状态测试的话,先在 PVE 里把 agent-01 回滚到 proxy_ok 快照(回滚后要点“启动”)。然后:
bash ~/agent-template.sh install # 中途会要求输入 dev 的密码
每一部分开头会显示蓝色的 == 标题 ==,完成的项显示绿色 ✓。全部跑完后:
- 退出 SSH 重新登录:让
docker用户组和代理变量生效 - 执行
bash ~/agent-template.sh check(见下一步)
第三步:check(随时检查)
bash ~/agent-template.sh check
| 类别 | 检查项 |
|---|---|
| 时区和时间 | 时区 America/New_York;NTP 已同步;和 Google 服务器时间相差 60 秒以内 |
| IP | 局域网 IP 在 192.168.50.x;出口 IP 和国家(不能是 CN);sudo 下出口 IP 一致;顺便显示不走代理时的宽带 IP |
| 代理 | 当前会话、apt、systemd 系统服务、systemd 用户服务都有代理;能连上 Claude API、OpenAI API;apt 用官方源 |
| 工具 | 用登录 shell 查 node、pnpm、docker、gh、claude、codex、opencode、t3(和 T3 通过 SSH 看到的环境一致);docker 免 sudo;Docker daemon 和容器代理 |
| 机器身份 | 主机名、machine-id、SSH 主机密钥、QEMU Guest Agent、linger;装了 T3 后台服务时,再查是否监听局域网、PATH 是否含 ~/.local/bin |
最后显示 “全部通过(N 项)” 就对了;有 ✗ 时退出码不为 0。常见的 ✗ 和修法:
| ✗ 项 | 修法 |
|---|---|
| 当前会话没有代理变量 / docker 要 sudo | 退出 SSH 重新登录(VS Code、tmux 里的旧会话也要重开) |
| systemd 用户服务没有代理变量 | systemctl --user daemon-reexec,装了 T3 服务再 t3 service restart(开了 linger 后用户管理器常驻,重新登录不会重读配置;新版 install 已自动处理) |
| Docker 后台服务没有代理 | sudo systemctl restart docker |
| T3 只监听本机(127.0.0.1) | 见第七步的 agent.conf |
第四步:做模板前的准备,拍快照
这些做进模板,以后每台克隆机就都自带了:
| 准备项 | 怎么做 |
|---|---|
| Mac 的 SSH 公钥(强烈建议) | 在 Mac 上:ssh-copy-id dev@<agent-01 的 IP>。所有克隆机都能从 Mac 免密登录,T3 桌面 App 的 SSH 方式也需要 |
| Claude 通用配置 | CLAUDE.md、settings.json、skills 放进 ~/.claude/(见 模板教程 2.2) |
| 公开仓库源码 | cd ~/NocoBase && git clone … 再 pnpm install。私有仓库不要放进模板 |
init 每台单独做。然后在 PVE:agent-01 → 快照 → 做快照,名称 dev_tools(只能用字母、数字、-、_,以字母开头),不勾选“包括内存”。
第五步:cleanup,转换成模板
- 右键 agent-01 → 克隆:快照选
dev_tools,VM ID9000,名称tpl-agent,模式完整克隆(从快照克隆只能完整克隆) - 把 agent-01 关机:9000 的身份和 agent-01 一样,同时开机会抢同一个 IP
- 启动 9000,从 Mac SSH 登录(用 agent-01 原来的 IP),执行:
bash ~/agent-template.sh cleanup
发现登录凭证时会列出来,确认删除;最后选“关机”。关机前不要重启它,否则会重新生成 machine-id 和密钥 - 右键 9000 → 转换成模板
- 重新启动 agent-01
第六步:克隆新 agent,init
- 右键 tpl-agent → 克隆:VM ID 如
201,名称agent-02,完整克隆。日常 agent 可以在 硬件 里把内存改成 8G、CPU 4 核 - 启动后在 概要 页看 IP,Mac 上
ssh dev@<IP>(提示主机密钥变了就先ssh-keygen -R <IP>) - 执行:
bash ~/agent-template.sh init agent-02
init 会依次问这些问题:
| 问题 | 建议 | 说明 |
|---|---|---|
| Git 用户名 / 邮箱 | 填 | 直接回车可跳过 |
| 登录 Claude | y | 给出一个链接,在 Mac 浏览器里打开授权 |
| 登录 Codex | 要用就 y | 设备码方式:codex login --device-auth,在 Mac 浏览器打开链接输入代码 |
| 登录 OpenCode | 要用就 y | opencode auth login,选模型服务商并填写凭证 |
| 登录 GitHub | y | 推荐每台一个细粒度 token:选 “Paste an authentication token” |
| 安装 T3 Code 后台服务 | y | 同时写入 agent.conf(PATH + 监听 0.0.0.0),最后显示浏览器访问地址 |
| 设置 T3 Connect | 要用手机就 y | 所有虚拟机用同一个 T3 Connect 账号 |
完成后:退出重新登录 → bash ~/agent-template.sh check;路由器里按 MAC 绑定固定 IP;Mac 的 ~/.ssh/config 加一段别名。
bash ~/agent-template.sh init agent-01(主机名不变,只做登录和 T3 后台服务)。agent.conf 的机器,按第七步手动补上,不用重新 init。第七步:连接 T3 Code(浏览器、Mac、手机)
| 方式 | 适合 | 需要 |
|---|---|---|
浏览器 http://<IP>:3773 | Mac、家里其他电脑 | 后台服务监听 0.0.0.0;每个浏览器 t3 pair 配对一次 |
| Mac 桌面 App(SSH) | 主力使用 | 免密 SSH;App 自己管理服务端 |
| 手机 App(T3 Connect) | 手机、在外面 | 每台执行一次 t3 connect,手机登录同一账号 |
7.1浏览器访问(默认端口 3773)
后台服务默认只监听 127.0.0.1,局域网访问不了;默认 PATH 也不含 ~/.local/bin,会找不到 claude / codex / opencode。新版 init 已自动处理;手动补的话:
mkdir -p ~/.config/systemd/user/t3code.service.d cat > ~/.config/systemd/user/t3code.service.d/agent.conf <<EOF [Service] Environment=T3CODE_HOST=0.0.0.0 Environment=PATH=$HOME/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin EOF systemctl --user daemon-reload t3 service restart sleep 3; ss -ltnp | grep 3773 # 应该是 0.0.0.0:3773 或 *:3773 t3 pair # 生成配对链接
把配对链接在 Mac 浏览器里打开(链接里是 127.0.0.1 / localhost 的话换成虚拟机 IP),之后直接访问 http://<IP>:3773。每台虚拟机各用自己的 IP,端口都是 3773。
T3CODE_HOST 是从 T3 程序里查到的环境变量(后台服务会把 systemd 的环境变量传给服务端),官方文档没写。这是 HTTP 明文地址,只在局域网和 Tailscale 里用,不要暴露到公网;app.t3.codes 网页版要求 HTTPS,不能用它连这个地址。7.2确认是后台服务在提供 3773
systemctl --user status t3code --no-pager | head -12 # active (running),进程树里有 t3 __service-launcher PID=$(ss -ltnp | grep 3773 | grep -o 'pid=[0-9]*' | cut -d= -f2) ps -o pid,cmd -p $(ps -o ppid= -p $PID) # 上一级是 t3 __service-launcher 就对了
最可靠的验证:sudo reboot,不登录 SSH,直接在浏览器打开地址,能打开说明开机自启和 linger 都没问题。
7.3Mac 桌面 App(SSH)
- Mac 上确认:
ssh dev@<IP> 'sh -lc "command -v claude codex opencode t3"'能打印 4 行路径 - T3 Code → Settings → Connections → Add environment → SSH,填
dev@<IP>或 SSH 别名 - 添加项目,比如
/home/dev/NocoBase/nocobase3;Ctrl+J打开的终端运行在虚拟机里
7.4手机(T3 Connect)
- 手机装 T3 Code App(App Store / Google Play)
- 每台虚拟机执行一次
t3 connect:在浏览器打开它给的链接,核对短码,批准。所有虚拟机用同一个 T3 Connect 账号 - 手机 App 登录同一个账号,列表里就是全部 agent。在家会自动走局域网直连,在外面走 T3 Connect 中转,手机上不用开 Tailscale
不想用 T3 Connect:在 Mac 终端里 SSH 进虚拟机执行 t3 pair,用手机 App 扫屏幕上的二维码(只在家里 Wi-Fi 或手机开着 Tailscale 时能用)。
日常维护
| 要做什么 | 命令 |
|---|---|
| 更新脚本 | 重新执行第一步的下载命令 |
| 补装新加进脚本的工具 | bash ~/agent-template.sh install(可重复执行) |
| 全面检查 | bash ~/agent-template.sh check |
| 升级 T3 Code(后台服务一起升级) | t3 update |
| 重启 / 查看 T3 后台服务 | t3 service restart / t3 service status |
| 升级 Claude Code / Codex / OpenCode | claude update / npm i -g @openai/codex / opencode upgrade |
| 更新模板 | 从 tpl-agent 克隆一台 → 更新 → cleanup → 转成新模板(如 tpl-agent-v2) |
实际踩过的坑
| 现象 | 原因 | 解决 |
|---|---|---|
curl ipinfo.io 是国内 IP,sudo curl 却是美国 IP | 还在执行脚本时的旧 SSH 会话里,/etc/environment 只在登录时读取 | 退出 SSH 重新登录 |
docker run 报 permission denied … docker.sock | 刚加入 docker 组,当前会话没生效 | 重新登录,或 newgrp docker |
T3 安装报 libatomic.so.1: cannot open shared object file | Ubuntu Server 默认没有 libatomic1 | sudo apt install -y libatomic1(脚本已包含) |
装完提示 Add /home/dev/.local/bin to your PATH | ~/.local/bin 是安装时才建的,当前会话 PATH 里没有 | 重新登录(~/.profile 会自动加上) |
| check:systemd 用户服务没有代理变量 | linger 让用户管理器常驻,没读到新配置 | systemctl --user daemon-reexec |
http://<IP>:3773 局域网打不开,本机 curl 127.0.0.1:3773 是 200 | 后台服务只监听 127.0.0.1 | 第七步的 agent.conf |
| 克隆机和 agent-01 拿到同一个 IP | machine-id 相同,DHCP 按它分配 | 做模板前 cleanup;直接从快照克隆的机器,第一次开机前先关掉 agent-01 |
Mac SSH 提示 REMOTE HOST IDENTIFICATION HAS CHANGED | 克隆机生成了新的主机密钥 | Mac 上 ssh-keygen -R <IP> |