干净服务器从零部署
这一页是写给谁的
你刚拿到一台全新 Ubuntu / Debian 服务器(云主机、自己电脑装的虚拟机、公司内网机器都算),想从零跑起 anet hub + 一两个节点 + Telegram 接入,端到端跑通。
每一步都带验证命令,文末有常见报错对照表(故障排查表)。
不是给已经装好 anet 的人看的,那个走 上手指南 或 升级指南。 已有 Hub 要搬到另一台机器,请走 迁移 Hub,不要把从零部署当数据恢复。
0. 前置
按安装装好 Node.js ≥ 22.13 和 Bun ≥ 1.2(两个都要装,Hub 由 Bun 运行)。之后要用 systemd、cron 或另一个用户启动 Hub 和节点时,先看安装页里关于 PATH 的说明。
1. 安装 anet CLI
npm install -g @sleep2agi/agent-network
anet -vanet -v 会列出 agent-node、commhub-server 是否已就位(首次使用时自动拉取),以及本机装了哪些可选 runtime CLI。后面任何启动出错,先看这里。
2. 起 Hub(推荐 tmux 挂着)
CommHub 是常驻进程,关终端就停。生产场景配 systemd(§8 持久化),快速验证用 tmux:
# 装 tmux(如果没装)
sudo apt install tmux -y # Ubuntu / Debian
# 起一个名叫 anet-hub 的会话挂 hub
tmux new -s anet-hub
anet hub start --host 0.0.0.0 --port 9200
# 看到下面这段就 OK
# CommHub MCP Server <version>
# REST: http://0.0.0.0:9200/api
# ✅ Admin account created
# username: admin
# password: anet-<22 位随机十六进制> ← 只打印这一次,当场存下按 Ctrl+B 然后 D 把 tmux 会话断开但保活。回来用 tmux a -t anet-hub 再 attach。
验证 hub 在跑(另一个终端):
curl -s http://127.0.0.1:9200/health | head -5
# 期望返 {"ok":true,"version":"<version>",...} 之类公网部署立刻改密
首次启动打印的随机密码只显示一次。任何 --host 0.0.0.0 公网部署都要立刻改成自己的强密码:
anet login --username admin --password '<启动时打印的密码>' --hub http://127.0.0.1:9200
anet passwd # 交互改强密码(≥ 8 位 + 非弱密码字典)或起 hub 时直接设:anet hub start --host 0.0.0.0 --username <your-admin> --password '<strong-pass>'。
端口被占?换端口或停旧 hub
# 查看谁占了端口
ss -tlnp | grep 9200
# 换端口
anet hub start --port 9201
# 或优雅停掉旧 hub (推荐)
anet hub stop # 默认端口 9200, SIGTERM → 3s grace → SIGKILL 兜底
anet hub stop --port 9201 # 非默认端口
anet hub status # 看当前 PID / 端口 / commhub-server 版本
# 万一以上不可用, 兜底手动停
HUB_PID=$(ss -tlnp | grep ':9200' | sed -E 's/.*pid=([0-9]+).*/\1/' | head -1)
kill "$HUB_PID"
# 或如果你的 hub 跑在 tmux 里, 直接 attach + Ctrl+C
tmux a -t anet-hub # 然后按 Ctrl+C 停, Ctrl+B D 留 tmux 会话较旧的版本(如 2.2.12)anet hub --help 不列出 stop / status,但命令本身可用:anet hub status 会返回 hub running / vX.Y.Z / pid N。
3. CLI 登录
第三个终端(保持 hub 那个 tmux 不动):
anet login --hub http://127.0.0.1:9200 --username admin --password '<启动时打印的密码>'登录后 Token 写到 ~/.anet/config.json,后续 anet node ... 命令自动带凭证。
anet whoami # 确认身份4. 建 Agent 节点(按 runtime 选)
anet node create my-bot向导会按这个顺序问你:
节点名 → runtime → (仅 claude-agent-sdk 才弹) vendor → model → API Key / 鉴权runtime 是第一道分叉,决定后面要不要配 vendor、要装什么依赖。 选单列出全部 7 个 runtime,下表是常用的几个;npm 包、主推模型和完整的 wizard 行为对照见 runtimes — Runtime 对比 (canonical):
| Runtime | 复杂度 | 适合 | wizard 后续 | 额外依赖 |
|---|---|---|---|---|
claude-code-cli(推荐入门) | ⭐ | 已经在用 Claude Code,想复用订阅 | 跳过 vendor + model,直接走本机 claude 登录态 | 本机已 claude auth login |
claude-agent-sdk | ⭐⭐ | 程序化用 Anthropic 兼容 API(MiniMax / 书生 / 小米 MiMo 等国产模型走这里) | 弹 vendor 子菜单 → 选 vendor → 选 model → 填 API Key | API Key |
codex-sdk | ⭐⭐⭐ | 写代码 / 跑命令,用 OpenAI Codex | 跳过 vendor,走 codex 登录态 | agent-node + codex CLI + codex login |
grok-build-acp | ⭐⭐⭐ | 用 xAI Grok Build 跑任务 | 跳过 vendor,走 grok 登录态 + GROK_CODE_XAI_API_KEY | grok CLI + grok login + GROK_CODE_XAI_API_KEY |
opencode-cli (preview) | ⭐⭐⭐ | 用公版 sst/opencode CLI 当多 vendor 前端(预览;latest 与 preview 的选单里都有) | 选 vendor preset (anthropic / openai),key 从 env 读 | opencode CLI + Anthropic/OpenAI env key |
runtime 默认项注意
向导默认高亮第一项(当前是 claude-agent-sdk),新手一路按 Enter 会落到这条要配 vendor + API Key 的路径上。建议手动选 claude-code-cli,入门最快。
向导不问 Telegram
建节点向导走完(上表所有步骤)就结束,全程不会问你要 Telegram bot token / 白名单 UID。Telegram 是建完节点后用单独命令 anet channel add telegram 加上去的(第 6 节)。
如果你看到 anet create 开头的提示里有 "optional Telegram channel" 那一行,不要以为向导会顺便配,实际不会。
完成后节点配置写到当前目录下:
.anet/nodes/my-bot/config.json验证:
anet node ls # 应列出 my-bot5. (codex-sdk 专属)额外装 agent-node + codex CLI
如果上一步选了 codex-sdk 或 claude-agent-sdk runtime,节点跑起来要 @sleep2agi/agent-node 包。它在首次使用时通过 npx 懒加载;如果没拉到,启动会报 agent-node is not installed or cannot report a version. Run: anet upgrade。
兜底手动装一次:
npm i -g @sleep2agi/agent-node
# 验证
agent-node --version # 应输出版本号codex-sdk runtime 还要装 codex CLI 并登录:
# 注意是 @openai/codex (CLI 工具), 跟 @openai/codex-sdk (codex-sdk runtime 拉的 SDK 库) 是两个 npm 包
npm i -g @openai/codex
codex login # 浏览器 OAuth
# 验证
codex --versionclaude-agent-sdk runtime 不需要装 codex / claude CLI,只要在节点 config 里填了对应 vendor 的 API Key(或对应 env vars ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN)就行。
6. 配 Telegram channel(可选)
如果你想从 Telegram 直接给 agent 发任务:
6.1 拿 bot token + 你的 Telegram User ID
- Telegram 里搜 @BotFather →
/newbot→ 一路按提示,最后给你一段bot-token(形如1234567:ABCDef...) - 拿你的 Telegram User ID(数字):找 @userinfobot 发任意消息,它会回你的 UID
6.2 给节点加 telegram channel
anet channel add telegram my-bot \
--bot-token <bot-token> \
--allow <uid>参数:
<bot-token>:BotFather 给的串<uid>:能给这个 bot 发任务的 Telegram User ID(多个用逗号隔开:--allow 11111,22222)
验证落地:
anet channel ls
# 应列出: my-bot (my-bot) telegram allow: <uid>想加更多人?
anet channel add telegram <node> --allow <new-uid-list> 会覆盖 allowlist,不是追加。要保留原来的人就把完整列表再传一遍(--allow 11111,22222,33333)。更多已知限制见 guide/channels.md。
7. 启动节点
# 推荐 tmux 挂着(跟 hub 同款,免得关终端停)
tmux new -s anet-my-bot
anet node start my-botclaude-code-cli 节点首次启动会弹「dev-channels 确认框」
claude-code-cli runtime 首次启动会弹 Claude Code 的 --dangerously-load-development-channels 确认框:
❯ 1. I am using this for local development
2. Exit按 1 + Enter。脚本化 / detached 启动时没人按会卡住,节点一直显示 offline。
兜底:先用 tmux 前台手动按一次,之后再考虑 systemd 接管。Claude Code 那个确认是会话级的,首次按完后续就不弹了。
看到 SSE connected 即节点上线,回 hub 那边 anet status 应列出 my-bot online。
按 Ctrl+B D 把 tmux 断开保活。
8. 持久化(systemd / tmux)
下面给两条可选路径:tmux 临时挂、systemd 单元长期跑。
8.1 tmux 临时挂(开发 / 验证)
机器重启会丢,需要手动重起:
- hub:
tmux new -s anet-hub+anet hub start --host 0.0.0.0 - 每个节点:
tmux new -s anet-<alias>+anet node start <alias> - 想接
@rebootcrontab 也行,但 PATH / nvm 这些非交互 shell 问题要先解决(见 第 0 节)
复核节点真起来,别只看 stdout ✅
起完每个节点跑一条:tmux has-session -t "=<alias>"; echo $? 应输出 0。= 必须写,裸名字是前缀匹配,会命中别的 session 假报绿。早于 2.3.0-preview.40 的版本在 detached 场景可能打印 ✅ started detached (tmux session live) 并 exit 0,但 tmux 里没有进程。批量起用 anet project up,它的退出码在 ≥ 2.3.0-preview.40 上可信。
8.2 systemd unit(生产 / 开机自启)
下面这套 unit 文件未经官方测试,按你的实际 anet 路径(which anet)+ 运行用户改一下就能用。改完跑 systemctl daemon-reload + enable --now。
Hub /etc/systemd/system/anet-hub.service:
[Unit]
Description=Agent Network Hub
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/home/youruser
# 用 which anet 拿到真实绝对路径替换 ↓
ExecStart=/home/youruser/.nvm/versions/node/v22.13.0/bin/anet hub start --host 0.0.0.0 --port 9200
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.targetNode(templated,一份 unit 跑 N 个节点)/etc/systemd/system/anet-node@.service:
[Unit]
Description=Agent Network Node %i
After=anet-hub.service
Requires=anet-hub.service
[Service]
Type=simple
User=youruser
WorkingDirectory=/home/youruser
ExecStart=/home/youruser/.nvm/versions/node/v22.13.0/bin/anet node start %i
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target启用:
sudo systemctl daemon-reload
sudo systemctl enable --now anet-hub
sudo systemctl enable --now anet-node@my-bot
sudo systemctl status anet-hub anet-node@my-bot踩坑提醒:
ExecStart必须填anet的绝对路径(which anet),systemd 不会读 nvm~/.bashrcUser=用你日常装 anet 的那个用户,不要用rootclaude-code-cliruntime 首次跑会弹 dev-channels 确认框(见 §7 启动节点),systemd 接管前先 tmux 前台跑一次按掉- 想要官方 unit / 改进上面这份?欢迎 PR 或来 GitHub Discussions 提
在容器里跑
仓库目前没有受维护的生产 compose 套件,仓库里的 Dockerfile 和 compose 文件用于测试或特定集成。在容器里跑时,把容器当成「带 Node.js 和 Bun 的 Ubuntu」,上面每一步的命令都一样。可以参考 tests/Dockerfile(Node.js + Bun + anet 的最小集)起步,生产上自行加多阶段构建、镜像 hash 固定和非 root 用户。
- 启动顺序不变:Hub → Dashboard →
anet login→anet node create→anet project up,容器化只是把它们分到不同 service。 - 首次启动慢:第一次
anet hub start会从 npm 拉固定版本的commhub-server,缓存在$HOME/.bun/install/cache,预热这个目录可以显著提速。 - 容器间互通:Dashboard 通过 REST + SSE 调 Hub 的
:9200,两者要在同一个 docker network,或把 Hub 端口发布到宿主机。容器里的localhost指容器自己。 - 持久化:节点状态在工作目录下的
.anet/nodes/<alias>/,Hub 数据在~/.commhub/,都要挂成 volume。 - 不要让节点进程当 PID 1:用
tini这类 init 包一层,否则 SIGTERM 会跳过节点的离线通知。
故障排查表
按部署步骤的顺序排列,报错 → 原因 → 解法:
| # | 现象 | 原因 | 解法 |
|---|---|---|---|
| 1 | anet hub start → spawn bunx ENOENT + node stack crash | 机器没装 Bun,commhub-server 是 Bun-shebang TS | npm i -g bun 或 curl -fsSL https://bun.sh/install | bash;之后 bun --version 应有输出 |
| 2 | anet node create 选完 runtime → FATAL: TypeError: fetch failed | 建节点要连本地 hub,但 hub 没起(多半因为第 1 条) | 另开终端先 anet hub start,再回这条重试 |
| 3 | 一路 Enter 落到要填 vendor + API Key 的复杂路径 | runtime 菜单默认高亮 claude-agent-sdk,不是最易上手的 claude-code-cli | 建节点时手动选 claude-code-cli(已 claude auth login 直接复用订阅)。中断 vendor 选择如果留下半成品节点,用 anet node delete <alias> 清掉重来 |
| 4 | 建完节点 Telegram 不工作,但向导开头说"optional Telegram channel" | 向导不问 Telegram,那行文案有误导 | Telegram 用 anet channel add telegram <node> --bot-token <tok> --allow <uid> 单独配(见 第 6 节) |
| 5 | anet node start (codex-sdk / claude-agent-sdk) → agent-node is not installed or cannot report a version | npx 懒加载没拉到 @sleep2agi/agent-node;≤ 2.3.0-preview.37 的构建(含 2.2.x)有这个问题 | 短路:npm i -g @sleep2agi/agent-node 让二进制就位;长期:anet upgrade 到 ≥ 2.3.0-preview.38(查通道指向用 npm view @sleep2agi/agent-network dist-tags) |
| 5.5 | anet node start 打 ✅ started detached (tmux session live) exit 0,但 tmux ls 找不到 session、进程也不在 | detached 路径的假报;早于 2.3.0-preview.40 的版本有这个问题 | 真判据:tmux has-session -t "=<alias>"; echo $? 应输出 0(= 必须)。批量场景用 anet project up(退出码在 ≥ 2.3.0-preview.40 上可信)。升级前,每次启动都用 has-session 复核 |
| 6 | claude-code-cli 节点起来后卡 offline / pane 卡在确认框 | Claude Code 的 --dangerously-load-development-channels 确认框等人按 Enter | 用 tmux 前台跑一次手动按 1 + Enter;后续就不弹了 |
| 7 | systemd / cron / 新用户启动报一连串 command not found | nvm + Bun 各自按用户装,非交互 shell 不加载 | 把 node/npm/bun 软链到 /usr/local/bin/,或启动脚本里显式 source ~/.nvm/nvm.sh |
| 8 | 机器重启全部掉线 | hub + 节点都靠手动 tmux 挂着 | 配 systemd 开机自启,参考 §8.2 systemd unit 里的模板 |
下一步
- 上手指南:已经装好 anet 的端到端走查(笔记本场景)
- 一键安装脚本退役说明:旧脚本已停用,请使用本页的分步流程
- 生产部署 / 公网部署安全:TLS / 防火墙 / 备份 / 公网风险点
- Channel 接入:当前渠道状态与 Telegram / 飞书接入;微信尚未发布
- 节点 Runtime:runtime 详细对比
如果踩到本页没覆盖的坑,欢迎到 GitHub Issues 开一条,写明哪一步、什么报错,附上 anet -v 输出。