跳转到内容

部署 Node / Docker

Node 宿主把权威状态写入 SQLite,把 Context 对象写入本地文件,并在同一服务中提供 HTTP、Dashboard 与设备 WebSocket。它适合单机自托管、内网、已有容器平台和需要本地强一致状态的场景。

如果你只想第一次试用,先完成5 分钟本地启动。如果你希望免维护主机或在边缘运行,比较 Cloudflare 一键部署源码部署

reverse proxy / TLS
│ HTTP + WebSocket
tool-bridge Node container
└── /data
├── state.sqlite3
└── objects/

Node/SQLite 的优点是认证、注册和搜索索引读写具有本地强一致语义。代价是状态属于这台主机和这块卷:多个无共享状态的副本不会自动组成一个集群,也不能靠负载均衡器合并各自的树。

本页以单实例容器为基线。需要多副本、自动故障转移或跨区恢复时,应先为 SQLite、对象数据和设备会话设计明确的一致性方案,而不是直接复制容器。

  • Docker 或兼容的容器运行时;
  • 可持久化并备份的本地卷;
  • 生产环境的 TLS 终结与域名;
  • 一项 Secret 注入机制;
  • Node.js 22+,仅用于生成 trust roots;
  • 已选定并固定一个镜像版本。
Terminal window
export TB_ADMIN_SK="$(node -e "console.log('tbk_'+require('crypto').randomBytes(32).toString('base64url'))")"
export TB_ENCRYPTION_KEY="$(node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))")"

把 Admin SK 保存到密码管理器,把两项值写入部署平台的 Secret。不要把真实值放进 Compose 文件、镜像层、Git 或普通环境配置。

已有 /data 状态时,TB_BOOTSTRAP_ADMIN_SK 不会覆盖现有管理员身份。丢失 Admin SK 不是通过重启并换一个环境变量就能恢复的。

<version> 替换为你已经评估的明确版本:

Terminal window
docker volume create tool-bridge-data
docker run -d --name tool-bridge \
--restart unless-stopped \
-p 127.0.0.1:8787:8787 \
-v tool-bridge-data:/data \
-e TB_BOOTSTRAP_ADMIN_SK="$TB_ADMIN_SK" \
-e TB_SECRET_ENCRYPTION_KEY="$TB_ENCRYPTION_KEY" \
ghcr.io/tokenrollai/tool-bridge:<version>

只把容器端口发布到回环地址,由反向代理负责公网或局域网入口。不要在没有 TLS、防火墙和访问策略的情况下把 8787 直接暴露到公网。

变量 作用 生产要求
TB_BOOTSTRAP_ADMIN_SK 首次引导 Admin SK 必须通过 Secret 注入;缺失时默认拒绝启动
TB_SECRET_ENCRYPTION_KEY SecretStore 主密钥 32 字节 base64url;通过 Secret 注入并备份
TB_DATA_DIR SQLite 与对象根目录 容器默认使用 /data;必须挂持久卷
TB_HOST / TB_PORT Node 监听地址和端口 通常保持容器内部默认,由端口映射控制暴露
TB_CANONICAL_ORIGIN 唯一规范 origin,固定 OAuth redirect 使用 OAuth 或多入口反代时应显式设置 HTTPS origin
TB_REMOTE_ALLOWLIST Federation host 后缀白名单 空值拒绝所有 remote
TB_MAX_HOPS Remote Via 跳数上限 保持有限值;不要用超大值绕过环保护
TB_UI_DIR 自定义 Dashboard 静态目录 通常不需要,默认从 dashboard 包加载

环境变量可能随版本演进。部署前用对应版本的 server 包说明和发布说明核对,不把本表当作永远完整的配置清单。

TB_ALLOW_INSECURE_BOOTSTRAP=trueTB_ALLOW_INSECURE_HTTP=true 都是本地开发逃生口,不应进入共享或生产环境。

反向代理必须:

  • 把唯一的 https://tb.example.com 转发到 http://127.0.0.1:8787
  • 保留 Authorization header;
  • 支持 WebSocket upgrade,供 tb connect 和设备会话使用;
  • 传递正确的原始 host/proto 语义;
  • 不把请求 body、SK、Authorization 或含敏感参数的 URL 写入普通访问日志;
  • 限制 Dashboard 和管理入口的网络暴露范围,不能以网络限制替代 SK 授权。

使用 OAuth 时设置:

TB_CANONICAL_ORIGIN=https://tb.example.com

上游 OAuth 应只登记这一规范 origin 的回调地址,避免内网地址、IP、HTTP 和正式域名同时参与回调。

Terminal window
curl --fail https://tb.example.com/healthz
tb login --base-url https://tb.example.com --profile production
tb use production
tb whoami
tb tree --depth 2
tb help system/status
tb call system/status --tool get

还应签发一把临时受限 SK,验证:

  • 授权路径可读、可调用;
  • 未授权路径返回 404;
  • Dashboard /ui 使用同一 SK 得到一致结果;
  • 如果需要设备连接,完成一次 tb connect、断线和重连;
  • ~describe 只返回实际装配的全局 capability;未装配 Search 时允许返回 404。

完整矩阵见生产上线检查清单

备份必须同时覆盖 SQLite 和 objects/。最简单的单实例策略是在停止写入后,对整个 /data 做一致快照。

停止容器后导出命名卷:

Terminal window
docker stop tool-bridge
docker run --rm \
-v tool-bridge-data:/data:ro \
-v "$PWD":/backup \
alpine \
tar czf /backup/tool-bridge-data.tgz -C /data .
docker start tool-bridge

备份包含 SK hash、SecretStore 密文与对象数据,但仍需要单独安全保管 TB_SECRET_ENCRYPTION_KEY 和 Admin SK。只有数据备份而没有加密根,不能完整恢复上游凭证。

恢复流程应在隔离环境定期演练:创建新卷、解压备份、使用同一加密密钥启动、验证 Admin/受限 SK、节点、Context 对象与一次真实调用。

  1. 阅读目标版本发布说明,确认 pre-launch 行为变化;
  2. 记录当前镜像 digest/版本,停止写入并备份 /data
  3. 拉取目标版本;
  4. 用相同卷和 Secret 重建容器;
  5. 依次验证 /healthz、Admin ~help、受限 SK、真实 Provider、Dashboard 和设备通道;
  6. 失败时停止新容器,恢复备份并使用原版本镜像。

不要只看容器 health 就宣布升级完成。数据面、权限和真实 Provider 才是可用性证据。

查看 docker logs tool-bridge。常见原因是缺 trust root、加密密钥格式错误、/data 无写权限或 SQLite 无法打开。

检查反向代理是否把所有路径错误地回退到前端 index.html。SPA fallback 应只服务 /ui,不能吞掉根 ~helpsystem/* 和数据面。

确认反向代理支持 WebSocket upgrade,没有为长连接设置过短请求超时,并且设备使用稳定 ID 和最小权限 SK。

通常是没有挂载预期卷、TB_DATA_DIR 指向另一路径,或创建了新卷。先停止写入,检查实际 mount,再决定恢复;不要反复 bootstrap 制造更多状态。