Files
openhuman/gitbooks/features/cloud-deploy.md
T

8.4 KiB

description, icon
description icon
Hosting the headless openhuman-core in the cloud - DigitalOcean App Platform or Docker Compose on any VPS. cloud

Cloud deployment

OpenHuman is a desktop app, but its Rust core (openhuman-core) is a headless JSON-RPC server that can be hosted in the cloud. Deploying the core separately is useful for:

  • Multi-device access, point several desktop clients at the same hosted core
  • Internal testers without local Rust toolchains
  • Long-running cron jobs / webhooks that should outlive a laptop session

This guide covers three deploy paths, easiest first:

  1. DigitalOcean App Platform: one-click
  2. DigitalOcean App Platform: manual via doctl
  3. Any VPS via Docker Compose

What gets deployed in every path: a single container running openhuman-core serve on port 7788, behind the provider's TLS. The desktop app already knows how to talk to a remote core, set OPENHUMAN_CORE_RPC_URL=https://your-host/rpc and OPENHUMAN_CORE_TOKEN=... in app/.env.local and launch.


What you need before you start

Setting Required Notes
OPENHUMAN_CORE_TOKEN yes Bearer token clients send to /rpc. Generate with openssl rand -hex 32. Anyone with this token can drive the core.
BACKEND_URL yes Tinyhumans backend the core talks to (https://api.tinyhumans.ai for prod).
OPENHUMAN_APP_ENV no production or staging. Defaults to production.
OPENHUMAN_CORE_HOST no Defaults to 0.0.0.0 in the container.
OPENHUMAN_CORE_PORT no Defaults to 7788.
RUST_LOG no info is fine; debug for triage.

Endpoints exposed by the running container:

  • GET /health, public liveness probe. Used by every deploy path's healthcheck.
  • POST /rpc, bearer-protected JSON-RPC entrypoint.
  • GET /events, GET /ws/dictation, public streaming channels.

The OPENHUMAN_WORKSPACE directory (/home/openhuman/.openhuman inside the container) holds the core's config, sqlite databases, and skill state. Mount it on a persistent volume in every production deploy or you will lose data on restart.


1. DigitalOcean App Platform: one-click

Click the button below to create a new App Platform application from this repository's .do/app.yaml:

Deploy to DO

Then, in the App Platform UI, before the first deploy completes:

  1. Open the Settings → App-Level Environment Variables tab.
  2. Replace the placeholder OPENHUMAN_CORE_TOKEN value with a strong secret (openssl rand -hex 32). Mark it encrypted.
  3. If you are deploying staging, change OPENHUMAN_APP_ENV to staging and BACKEND_URL to https://staging-api.tinyhumans.ai.
  4. Hit Save. App Platform redeploys with the new secret.

App Platform handles TLS, restart-on-crash, log streaming, and rolling redeploys on git push (set deploy_on_push: true in .do/app.yaml to opt-in).

Persistence note: App Platform Basic does not provide block storage. The core's workspace lives in the container's ephemeral filesystem and is lost on redeploy. For durable storage, attach a managed database or upgrade to a tier that supports volumes. See the Compose path for a self-host alternative with persistent volumes out of the box.


2. DigitalOcean App Platform: manual via doctl

If you'd rather not click through the UI:

# One-time: install doctl and authenticate.
doctl auth init

# Edit .do/app.yaml - set OPENHUMAN_CORE_TOKEN to a real value (or pass it in
# at create time via --spec with envsubst). Then:
doctl apps create --spec .do/app.yaml

# Watch the build:
doctl apps list
doctl apps logs <app-id> --type build --follow

Update an existing app after editing the spec:

doctl apps update <app-id> --spec .do/app.yaml

3. Any VPS via Docker Compose

Works on any host with Docker Engine ≥ 24 and the Compose plugin. DigitalOcean Droplet, Hetzner, Linode, EC2, a home server.

Each production release publishes a multi-tagged image to GHCR:

docker pull ghcr.io/tinyhumansai/openhuman-core:latest        # tracks the latest prod cut
docker pull ghcr.io/tinyhumansai/openhuman-core:v1.2.4        # pinned by GitHub Release tag
docker pull ghcr.io/tinyhumansai/openhuman-core:1.2.4         # pinned by SemVer

The image is linux/amd64. arm64 hosts pull the standalone tarball attached to the same GitHub Release (openhuman-core-<version>-aarch64-unknown-linux-gnu.tar.gz) or build the image from source on an arm64 builder.

Quick run with a published image:

docker run -d --name openhuman-core -p 7788:7788 \
  -e OPENHUMAN_CORE_TOKEN="$(openssl rand -hex 32)" \
  -e BACKEND_URL=https://api.tinyhumans.ai \
  -e OPENHUMAN_APP_ENV=production \
  -v openhuman-workspace:/home/openhuman/.openhuman \
  ghcr.io/tinyhumansai/openhuman-core:latest

Or use the in-repo Compose file (still builds the image locally from Dockerfile; switch the image: field to ghcr.io/tinyhumansai/openhuman-core:latest in docker-compose.yml to consume the published image instead):

# On the server:
git clone https://github.com/tinyhumansai/openhuman.git
cd openhuman

# Configure secrets:
cp .env.example .env
# Edit .env - at minimum:
#   BACKEND_URL=https://api.tinyhumans.ai
#   OPENHUMAN_CORE_TOKEN=<openssl rand -hex 32>
#   OPENHUMAN_APP_ENV=production

# Build and start:
docker compose up -d

# Verify:
docker compose ps
curl -fsS http://localhost:7788/health

Headless install without Docker

If you can't run Docker on the host, grab the standalone CLI tarball attached to the latest GitHub Release:

# Pick the tarball that matches your host arch.
ARCH="$(uname -m)"
case "$ARCH" in
  x86_64)  TARGET=x86_64-unknown-linux-gnu  ;;
  aarch64) TARGET=aarch64-unknown-linux-gnu ;;
  *) echo "Unsupported arch: $ARCH"; exit 1 ;;
esac
VERSION=1.2.4   # set to the release you want
curl -fsSL "https://github.com/tinyhumansai/openhuman/releases/download/v${VERSION}/openhuman-core-${VERSION}-${TARGET}.tar.gz" \
  | tar -xz -C /usr/local/bin
openhuman-core --version

Then run openhuman-core serve under your service manager of choice (systemd, supervisord, …) with the same environment variables documented above.

The Compose file (docker-compose.yml) maps the core on :7788, mounts a named volume openhuman-workspace for persistence, and sets restart: unless-stopped so the core comes back after host reboots.

Updating

git pull
docker compose build
docker compose up -d

Logs

docker compose logs -f openhuman-core

Putting it behind TLS

Use Caddy, nginx, or Traefik as a reverse proxy in front of :7788. A minimal Caddyfile:

core.example.com {
  reverse_proxy localhost:7788
}

Pointing the desktop app at a hosted core

In the desktop app's environment file (app/.env.local):

# Use the hosted core instead of spawning a local sidecar.
OPENHUMAN_CORE_RUN_MODE=external
OPENHUMAN_CORE_RPC_URL=https://core.example.com/rpc
OPENHUMAN_CORE_TOKEN=<the same token you set on the server>

Restart the desktop app. The provider chain in App.tsx will route all RPC calls to the remote core; nothing else changes.


Smoke test

The repo ships .github/workflows/deploy-smoke.yml, which runs on every PR that touches the deploy artifacts. It builds the Docker image, boots it, and polls /health, so a regression in the cloud deploy path fails CI before it lands on main.

To run the same check locally:

docker build -t openhuman-core:smoke .
docker run -d --name oh-smoke -p 7788:7788 \
  -e OPENHUMAN_CORE_TOKEN=smoke-test-token \
  openhuman-core:smoke
# Wait ~15s for the binary to come up, then:
curl -fsS http://localhost:7788/health
docker rm -f oh-smoke