pages.chenos.dev / workstation / agent 模板脚本

手把手:用 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 退出)。

虚拟机还没配代理也能下载:pages.chenos.dev 在 Cloudflare 上,国内一般能直接访问。下载不了的话,在 Mac 浏览器里打开 脚本链接,全选复制,在虚拟机里 nano ~/agent-template.sh 粘贴保存。

第二步:install(模板源机器)

想从干净状态测试的话,先在 PVE 里把 agent-01 回滚到 proxy_ok 快照(回滚后要点“启动”)。然后:

bash ~/agent-template.sh install        # 中途会要求输入 dev 的密码

每一部分开头会显示蓝色的 == 标题 ==,完成的项显示绿色 ✓。全部跑完后:

  1. 退出 SSH 重新登录:让 docker 用户组和代理变量生效
  2. 执行 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。私有仓库不要放进模板
这一步不要登录 Claude、Codex、OpenCode、GitHub、T3 Connect。登录在克隆后由 init 每台单独做。

然后在 PVE:agent-01 → 快照 → 做快照,名称 dev_tools(只能用字母、数字、-、_,以字母开头),不勾选“包括内存”。

第五步:cleanup,转换成模板

  1. 右键 agent-01 → 克隆:快照选 dev_tools,VM ID 9000,名称 tpl-agent,模式完整克隆(从快照克隆只能完整克隆)
  2. 把 agent-01 关机:9000 的身份和 agent-01 一样,同时开机会抢同一个 IP
  3. 启动 9000,从 Mac SSH 登录(用 agent-01 原来的 IP),执行:
    bash ~/agent-template.sh cleanup
    发现登录凭证时会列出来,确认删除;最后选“关机”。关机前不要重启它,否则会重新生成 machine-id 和密钥
  4. 右键 9000 → 转换成模板
  5. 重新启动 agent-01

第六步:克隆新 agent,init

  1. 右键 tpl-agent → 克隆:VM ID 如 201,名称 agent-02,完整克隆。日常 agent 可以在 硬件 里把内存改成 8G、CPU 4 核
  2. 启动后在 概要 页看 IP,Mac 上 ssh dev@<IP>(提示主机密钥变了就先 ssh-keygen -R <IP>)
  3. 执行:
    bash ~/agent-template.sh init agent-02

init 会依次问这些问题:

问题建议说明
Git 用户名 / 邮箱填直接回车可跳过
登录 Claudey给出一个链接,在 Mac 浏览器里打开授权
登录 Codex要用就 y设备码方式:codex login --device-auth,在 Mac 浏览器打开链接输入代码
登录 OpenCode要用就 yopencode auth login,选模型服务商并填写凭证
登录 GitHuby推荐每台一个细粒度 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 加一段别名。

模板母本 agent-01 本身也要执行一次:bash ~/agent-template.sh init agent-01(主机名不变,只做登录和 T3 后台服务)。
已经用旧版脚本 init 过、没有 agent.conf 的机器,按第七步手动补上,不用重新 init。

第七步:连接 T3 Code(浏览器、Mac、手机)

方式适合需要
浏览器 http://<IP>:3773Mac、家里其他电脑后台服务监听 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)

  1. Mac 上确认:ssh dev@<IP> 'sh -lc "command -v claude codex opencode t3"' 能打印 4 行路径
  2. T3 Code → Settings → Connections → Add environment → SSH,填 dev@<IP> 或 SSH 别名
  3. 添加项目,比如 /home/dev/NocoBase/nocobase3;Ctrl+J 打开的终端运行在虚拟机里

7.4手机(T3 Connect)

  1. 手机装 T3 Code App(App Store / Google Play)
  2. 每台虚拟机执行一次 t3 connect:在浏览器打开它给的链接,核对短码,批准。所有虚拟机用同一个 T3 Connect 账号
  3. 手机 App 登录同一个账号,列表里就是全部 agent。在家会自动走局域网直连,在外面走 T3 Connect 中转,手机上不用开 Tailscale

不想用 T3 Connect:在 Mac 终端里 SSH 进虚拟机执行 t3 pair,用手机 App 扫屏幕上的二维码(只在家里 Wi-Fi 或手机开着 Tailscale 时能用)。

一个 T3 服务端就能同时跑多个项目、多个对话;要更多算力或隔离,就多开几台 agent 虚拟机,每台一个后台服务。Mac 的 Settings → Connections → Load balancing 可以让新对话自动分配到空闲的机器。

日常维护

要做什么命令
更新脚本重新执行第一步的下载命令
补装新加进脚本的工具bash ~/agent-template.sh install(可重复执行)
全面检查bash ~/agent-template.sh check
升级 T3 Code(后台服务一起升级)t3 update
重启 / 查看 T3 后台服务t3 service restart / t3 service status
升级 Claude Code / Codex / OpenCodeclaude 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 fileUbuntu Server 默认没有 libatomic1sudo 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 拿到同一个 IPmachine-id 相同,DHCP 按它分配做模板前 cleanup;直接从快照克隆的机器,第一次开机前先关掉 agent-01
Mac SSH 提示 REMOTE HOST IDENTIFICATION HAS CHANGED克隆机生成了新的主机密钥Mac 上 ssh-keygen -R <IP>