For the complete documentation index, see llms.txt. This page is also available as Markdown.

云端部署

在云中托管无头的 openhuman-core——DigitalOcean App Platform、Fly.io,或在任意 VPS 上使用 Docker Compose。

OpenHuman 是一个桌面应用,但其 Rust 核心 (openhuman-core) 是一个可托管在云端的无头 JSON-RPC 服务器。将核心单独部署适用于:

  • 多设备访问,让多个桌面客户端指向同一个托管核心

  • 没有本地 Rust 工具链的内部测试人员

  • 应当在笔记本会话结束后仍继续运行的长期 cron 任务 / webhook

本指南涵盖四种部署路径,按从最简单到最复杂排序:

每种路径都会部署的内容:运行一个单容器 openhuman-core serve 端口 7788。公网主机应位于提供商的 TLS 之后,例如 https://core.example.com/rpc。仅限私有访问的主机位于 localhost、RFC1918 网络或诸如 Tailscale 这样的 tailnet 上时,可以使用明文 HTTP,例如 http://100.x.x.x:7788/rpc,当核心无法从公网访问时。桌面应用已经知道如何与远程核心通信;请设置 OPENHUMAN_CORE_RPC_URL 以及 OPENHUMAN_CORE_TOKEN=...app/.env.local 并启动。


远程 UI 选项

OpenHuman 支持的远程部署方式是 核心远程,UI 本地:在 openhuman-core Linux 服务器上运行,并让桌面客户端指向该 RPC URL。已部署的核心目前还不会以生产 Web 应用的形式提供完整的 React/Tauri UI。仅桌面端的功能仍然需要 Tauri 壳层,包括托盘控制、原生深度链接、CEF 账号扫描器、操作系统钥匙串集成,以及窗口/屏幕相关能力。

如果你今天想在私有服务器上获得可通过浏览器访问的 UI,请使用 Vite Web 构建作为面向远程核心的开发/预览界面:

# 在服务器上,用显式 token 运行核心。
export OPENHUMAN_CORE_HOST=0.0.0.0
export OPENHUMAN_CORE_PORT=7788
export OPENHUMAN_CORE_TOKEN="$(openssl rand -hex 32)"
openhuman-core serve

# 在服务器上的另一个 shell 中,仅在回环地址上提供 UI。
pnpm --dir app dev -- --host 127.0.0.1 --port 1420

然后从你的工作站转发这两个端口:

打开 http://127.0.0.1:1420,在首次运行界面选择远程/核心选项,然后输入 http://127.0.0.1:7788/rpc 再加上 OPENHUMAN_CORE_TOKEN 来自服务器的值。

如果你从非回环来源提供浏览器 UI,请将该精确来源加入核心的 CORS 允许列表:

诸如以下的 Vite 回环来源: http://127.0.0.1:1420 以及 http://localhost:1420 会自动获准。公共 http:// 来源不建议使用,因为每次 RPC 调用都会携带持有者令牌。


持有者令牌的唯一事实来源

每个 /rpc 调用都会携带 Authorization: Bearer <token>。核心在启动时有两种方式加载该令牌(src/core/auth.rs):

  1. OPENHUMAN_CORE_TOKEN 环境变量:由调用方预先注入(Tauri 壳层、Docker、App Platform、systemd 单元,……)。核心会原样使用该值,并且 从不 写入文件。

  2. {workspace}/core.token 文件:由核心在首次启动时生成 仅当 OPENHUMAN_CORE_TOKEN 未设置时。独立的 openhuman core run 会使用它,以便 CLI 客户端可以 cat 读取该文件。

对于任何远程 / 容器化部署的经验法则:始终设置 OPENHUMAN_CORE_TOKEN. 不要依赖 core.token 在容器中。临时文件系统在重新部署时会丢失它,而任何试图从容器外读取该文件的客户端都会得到过期或空值。这两种路径在启动时被刻意设计为互斥;混用它们是“我重新部署后仪表板变成 401”的最常见原因。

要检查当前 正在运行的 核心正在使用什么,请运行 scripts/print-core-token.sh 在主机上(或在容器内配合 docker compose exec):

桌面应用的首次运行选择器也提供一个 测试连接 按钮,位于 Core RPC URL + token 字段旁边,它会触发 core.ping 使用输入的令牌对该 URL 发起请求并报告 已连接 ✓ / 认证失败 / 无法访问 在保存配置前内联完成。


开始前你需要准备的内容

设置项
必需
备注

OPENHUMAN_CORE_TOKEN

客户端发送到的持有者令牌 /rpc。生成方式: openssl rand -hex 32. 任何持有此令牌的人都可以控制核心。

BACKEND_URL

核心连接的 Tinyhumans 后端(https://api.tinyhumans.ai 用于生产环境)。

OPENHUMAN_APP_ENV

productionstaging。默认值为 production.

OPENHUMAN_CORE_HOST

默认为 0.0.0.0 在容器中。

OPENHUMAN_CORE_PORT

默认为 7788.

RUST_LOG

info 就可以; debug 用于故障排查。

运行中的容器暴露的端点:

  • GET /health,公开存活探针。每种部署路径的健康检查都会用到。

  • POST /rpc,受持有者令牌保护的 JSON-RPC 入口。

  • GET /events, GET /ws/dictation,公开流式通道。

这个 OPENHUMAN_WORKSPACE 目录(/home/openhuman/.openhuman 在容器内)保存核心的配置、sqlite 数据库和技能状态。 将其挂载到持久卷上 ,用于每次生产部署,否则重启时会丢失数据。


1. DigitalOcean App Platform:一键部署

点击下面的按钮,基于此仓库的 .do/app.yaml:

Deploy to DO

然后,在 App Platform 界面中, 在第一次部署完成之前:

  1. 打开 Settings → App-Level Environment Variables 选项卡。

  2. 将占位符 OPENHUMAN_CORE_TOKEN 值替换为一个强随机密钥(openssl rand -hex 32)。将其标记为加密。

  3. 如果你在部署预发布环境,请将 OPENHUMAN_APP_ENV 改为 staging 以及 BACKEND_URL 改为 https://staging-api.tinyhumans.ai.

  4. 点击 保存。App Platform 会用新密钥重新部署。

App Platform 负责 TLS、崩溃自动重启、日志流以及基于 git push (设置 deploy_on_push: true.do/app.yaml 即可启用)。

持久化说明: App Platform Basic 不提供块存储。核心的工作区位于容器的临时文件系统中,重新部署时会丢失。若要持久存储,请挂载托管数据库,或升级到支持卷的套餐。请参见 Compose 路径 ,了解开箱即带持久卷的自托管替代方案。


2. DigitalOcean App Platform:通过 doctl 手动部署

如果你不想在 UI 中点来点去:

编辑 spec 后更新现有应用:


3. 任何通过 Docker Compose 的 VPS

适用于任何安装了 Docker Engine ≥ 24 和 Compose 插件的主机。DigitalOcean Droplet、Hetzner、Linode、EC2、家用服务器都可以。

每个生产发布都会向 GHCR 发布一个带多个标签的镜像:

该镜像为 linux/amd64。arm64 主机请下载同一 GitHub Release 附带的独立 tar 包(openhuman-core-<version>-aarch64-unknown-linux-gnu.tar.gz)或者在 arm64 构建机上从源码构建镜像。

使用已发布镜像快速运行:

或者使用仓库内的 Compose 文件(仍会从以下内容在本地构建镜像: Dockerfile;将 image: 字段改为 ghcr.io/tinyhumansai/openhuman-core:latestdocker-compose.yml ,即可改为使用已发布的镜像):

无 Docker 的无头安装

如果你无法在主机上运行 Docker,请获取最新版本附带的独立 CLI tar 包 GitHub Release:

然后在 openhuman-core serve 在你选择的服务管理器(systemd、supervisord、……)下使用上文记录的相同环境变量运行。

无头自更新约定

无头部署应将 openhuman.update_apply 视为安全原语:它会下载发布产物,将其原子写入到当前二进制旁边,然后返回。不会自动退出任何进程。

openhuman.update_run 遵循 config.update.restart_strategy:

  • self_replace (默认):暂存二进制,发布进程内重启请求,然后让正在运行的核心自行重新生成。

  • supervisor:暂存二进制并返回 restart_requested=false。你的外部服务管理器必须重启该进程。

对于长期运行的 Linux 服务,请设置:

或者等效的环境变量:

推荐 systemd 配置:

运维流程:

  1. 调用 openhuman.update_check 以发现可用发布。

  2. restart_strategy = "supervisor" 你的 update.toml (或者设置 OPENHUMAN_AUTO_UPDATE_RESTART_STRATEGY=supervisor),这样核心就会暂存新二进制而不会尝试自我重新执行,然后调用 openhuman.update_applyopenhuman.update_run. restart_strategy 是一个配置项,不是 RPC 参数。

  3. 显式重启该单元: systemctl restart openhuman.

如果下载或暂存失败,正在运行的二进制会保留在原处,并且不会请求重启。如果暂存的二进制在重启后证明有问题,请通过包管理器、镜像标签或发布产物恢复到之前的二进制,然后再次重启 supervisor。

Compose 文件(docker-compose.yml)将核心映射在 :7788,挂载名为 openhuman-workspace 以实现持久化,并设置 restart: unless-stopped ,从而在主机重启后核心会自动恢复。

更新

对于暴露 RPC 的生产部署,建议保持会修改状态的更新 RPC 处于禁用(OPENHUMAN_AUTO_UPDATE_RPC_MUTATIONS_ENABLED=false)状态,并通过现有的镜像标签或包管理流程来完成发布。

日志

轮换持有者令牌

OPENHUMAN_CORE_TOKEN 是公网与完整 RPC 访问之间的唯一防线。请按计划轮换,并在任何疑似泄露后立即轮换:

对于 App Platform,在其中也这样做 Settings → App-Level Environment Variables: 编辑 OPENHUMAN_CORE_TOKEN secret 并让 App Platform 重新部署。无需删除单独的 token 文件;env var 是唯一的状态。

将其置于 TLS 之后

在……前面使用 Caddy、nginx 或 Traefik 作为反向代理 :7788. 一个最小的 Caddyfile:


将桌面应用指向托管的 core

在桌面应用的环境文件(app/.env.local):

对于一个没有公网 IP、仅限私有 tailnet 的 VM,请改用 tailnet URL:

重启桌面应用。中的提供者链 App.tsx 将把所有 RPC 调用路由到远程 core;其他都不变。公共 http:// 宿主会被应用选择器拒绝;对于任何可公开访问的 core,请使用 HTTPS。

故障排查:在云运行时上 OAuth 之后登录失败

症状:浏览器中的 OAuth 完成(“关闭此窗口并返回应用”),但桌面端随后显示登录错误——而 相同 账户在本地(嵌入式)运行时登录正常(issue #3025)。

根本原因几乎总是 远程 core,而不是桌面端。 auth_store_session 让 core 在持久化之前先把新的 session token 与后端进行验证(GET /auth/me);在云运行时中,这个调用是在你的服务器上执行的,所以如果远程 core 无法连接/认证后端,它就会失败:

  • BACKEND_URL 未设置或错误。 这是必需的(见上面的环境变量表),并且必须是 https://api.tinyhumans.ai 用于生产环境(或 staging URL)。缺少该值是最常见的原因——有一位报告者的失败原因正是如此。

  • 后端从服务器上不可达 (出站防火墙、DNS、TLS 拦截)→ core 在 /auth/me.

  • 过时的 core。 较旧的 core 早于 allowPendingBackendValidation 并且在没有宽限期的情况下同步验证;请将服务器更新到当前版本。

  • 错误的 RPC token。 token 不匹配会在 /rpc上表现为 HTTP 401;请重新粘贴 token(见“轮换 bearer token”)。

检查远程 core 日志中的 Session validation failed (GET /auth/me) 以及状态/原因。现在桌面端会针对这些情况报告云端特定、可操作的消息,而不是通用的“请重试”(issue #3025)。


命名卷所有权与 Docker entrypoint

Docker 默认创建的命名卷归 root:root 所有。由于 core 以非 root 的 openhuman 用户(UID 10001)运行,横幅后第一次写入(init_rpc_token → write_token_file$OPENHUMAN_WORKSPACE)如果没有先修复所有权,就会抛出 Permission denied (os error 13)

该镜像带有一个专用 entrypoint,位于 /usr/local/bin/docker-entrypoint-core.sh 它会:

  1. root.

  2. 启动 运行 + mkdir -p 和 chown openhuman:openhuman $OPENHUMAN_WORKSPACE 以及 $HOME/.openhuman 两处(目录 core.tokenOPENHUMAN_CORE_TOKEN 未设置时会写入)。

  3. 调用 exec gosu openhuman openhuman-core "$@" 以降权并交给二进制程序。

这是 幂等的:在新创建的卷上,chown 会修复 root 拥有的目录;在已经修复过的卷上,chown 则不产生任何效果。从预先修复之前的镜像升级时,无需手动 docker volume rm

该 entrypoint 名为 docker-entrypoint-core.sh 并且只 接入 root Dockerfile。E2E 镜像(e2e/docker-entrypoint.sh)不受影响。


4. Fly.io

Fly.io 非常适合 openhuman-core:它会自动处理 TLS,支持所有层级的持久化卷,并且可以在空闲时自动停止机器以降低成本。

前提条件

  • flyctl 已安装并已认证(fly auth login)

  • 一个 Fly.io 账户

步骤 1:启动应用

Fly.io 会自动检测 Dockerfile 。选择一个靠近用户的区域,并在提示时跳过第一次部署。这会生成一个配置文件。

步骤 2:配置 .fly/fly.toml

仓库中在 .fly/fly.toml提供了一个模板。填写 <你的应用名称> 以及 <你的区域> 为你在 fly launch:

步骤 3:创建持久化卷

将工作区挂载到持久化卷上 否则每次重新部署都会丢失数据。

步骤 4:设置密钥

保存 OPENHUMAN_CORE_TOKEN的值。之后连接桌面应用时会用到它。 任何拥有这个 token 的人都可以控制 core;请像对待密码一样对待它,并在 fly secrets set OPENHUMAN_CORE_TOKEN="$(openssl rand -hex 32)" 之后旋转它。

步骤 5:部署

验证 core 是否健康:

步骤 6:将桌面应用指向托管的 core

app/.env.local:

或者使用 首次运行选择器 在桌面应用中(Core RPC URL + token 字段旁有一个 测试连接 按钮)进行配置,无需编辑文件。

持续部署

要在每次推送到 main时自动重新部署,请在 .github/workflows/fly-deploy.yml:

使用 fly tokens create deploy 生成一个部署 token,并将其作为名为 FLY_API_TOKEN.

更新

对于固定版本号的部署,请在 .fly/fly.toml 中更新镜像标签,然后重新部署:

日志

已知坑:卷上的 UID 不匹配

如果你在从 Dockerfile 构建(它会创建 openhuman 用户,UID 为 10001)和拉取预构建的 GHCR 镜像(它使用 UID 1000)之间切换,那么已经写入持久化卷的文件会归旧 UID 所有,并在 Permission denied (os error 13) 启动时产生

同样的事情也会发生在经历过镜像升级的 Docker 命名卷上,以及任何被 root docker exec 写入过的工作区上—— docker exec 不会运行 entrypoint,因此会以 root 身份落地并留下一个 root:root config.toml (core 会以 0600 权限写入它,所以运行时用户之后根本无法打开它)。

scripts/docker-entrypoint-core.sh 现在会自动修复此问题:它会在每次启动时递归地 chown 工作区, 跳过已经正确归属的条目。如果修复无法运行—— cap_drop: ALL 在没有 cap_add: CHOWN 的情况下——entrypoint 会拒绝启动,而不是启动一个会对 /health 返回 200、而每个配置 RPC 都返回 Permission denied (os error 13)的容器,并打印确切的 chown 要运行的命令。请在容器日志中查找 [docker-entrypoint] pre-heal / FATAL 行。

通过 SSH 进入并重新设置工作区所有者来修复旧容器:

Docker 对应做法。不要硬编码这些 id,而要从容器中推导出来,这样无论运行的是哪个镜像都能保持正确:

在修复之前查看哪个 UID 拥有什么。注意 docker exec 默认是 root,所以应明确询问运行时用户,而不要相信一个裸的 id:


冒烟测试

有两种失败模式会保护云部署路径:

  • docker-image: 设置 OPENHUMAN_CORE_TOKEN 并且不挂载任何卷。保护 DigitalOcean App Platform 路径(.do/app.yaml),在那里 token 总是预先设置好,并且不使用持久化卷。

  • docker-volume-permissions: 省略 OPENHUMAN_CORE_TOKEN 并在 /home/openhuman/.openhuman处挂载一个全新的匿名卷。重现 issue #2065 的精确失败模式,并断言 /health 返回 200,且 Permission denied (os error 13) 不出现在日志中。

在本地运行冒烟检查:

最后更新于