— self-host

Run your own
agent platform.

Two commands and you have the whole thing: multi-tenant auth, billing, 14 tools, memory, vibe coding, and a dedicated agent per paying user. One SQLite file, three Bun processes, no external services required to boot.

Hermes Agent runtime

Read live from the upstream release feed every time this page is opened, so it never drifts out of date. ChatHermes talks to Hermes Agent over an OpenAI-compatible endpoint, so a runtime upgrade does not require a ChatHermes upgrade.

Before you start

Pick a path

Your machine

~3 min

The fastest way to see it running. Interactive setup wizard, dependency install, build, and a smoke test — then all three services.

git clone https://github.com/kwkuh/chathermes.git
cd chathermes
./bin/install.sh     # wizard + deps + build + smoke test
./bin/start.sh       # boots orchestrator, web, and the shared agent proxy

Open http://localhost:7000 and sign in with any email.

A VPS you own

~10 min

Same install, then systemd units so it survives reboots. Put nginx and Certbot in front for HTTPS. A $5 box is enough to start.

git clone https://github.com/kwkuh/chathermes.git /opt/chathermes
cd /opt/chathermes && ./bin/install.sh
cp deploy/systemd/*.service /etc/systemd/system/
systemctl enable --now chathermes-orch chathermes-web chathermes-hermes-proxy

Full production notes — HTTPS, Stripe webhooks, verified email domain — are in INSTALL.md. INSTALL.md

Docker

~2 min

One image runs all three processes and keeps every byte of state in one volume. This is the path that works on any platform that can run a container.

git clone https://github.com/kwkuh/chathermes.git && cd chathermes
cp orchestrator/.env.example .env    # set SESSION_SECRET + one LLM key
docker compose up -d

On macOS, port 7000 is taken by AirPlay Receiver — run WEB_PORT=7600 docker compose up -d, or turn AirPlay off in System Settings.

One-click to Hetzner

~2 min

Provision a server from inside the admin panel with your own Hetzner token. Cloud-init installs and boots everything. This is also what provisions a dedicated agent per Pro user.

# from a running instance:
#   Admin → Hetzner → pick server type + region → Deploy

Needs HETZNER_API_TOKEN in the orchestrator env. Gated by default: an admin approves every spawn.

Any other cloud

Hetzner is wired into the admin panel because that is what the hosted product uses. Nothing about ChatHermes is tied to it. Paste the block below as user data when you create a server and it installs itself on first boot — same script the one-click deploy runs.

#cloud-config
package_update: true
packages: [docker.io, docker-compose-plugin, git]
write_files:
  - path: /opt/chathermes/.env
    permissions: '0600'
    content: |
      SESSION_SECRET=REPLACE_WITH_openssl_rand_hex_32
      PUBLIC_BASE_URL=https://your-domain.com
      NOUS_API_KEY=REPLACE_OR_USE_ANOTHER_PROVIDER
      DATA_ROOT=/data
runcmd:
  - systemctl enable --now docker
  - git clone https://github.com/kwkuh/chathermes.git /opt/chathermes/repo
  - cp -r /opt/chathermes/repo/. /opt/chathermes/
  - cd /opt/chathermes && docker compose up -d --build
DigitalOcean
Droplet → Advanced → Add Initialization scripts (user data). Or: doctl compute droplet create --user-data-file cloud-init.yml
Vultr
Deploy → Advanced → Cloud-Init User-Data. Or: vultr-cli instance create --userdata
Linode / Akamai
Create Linode → Advanced → Metadata → User Data (needs a metadata-enabled region)
AWS EC2 / Lightsail
Launch instance → Advanced details → User data. Ubuntu images ship with cloud-init
Google Cloud
Create VM → Advanced → Automation → Startup script (paste the runcmd lines as a shell script)
Azure
VM → Advanced → Custom data and cloud init
Scaleway
Instance → Advanced settings → cloud-init
OVHcloud
Public Cloud instance → Post-installation script
Oracle Cloud
Instance → Advanced options → Cloud-init script. The Always Free ARM tier fits this comfortably
Contabo / Netcup
Any Ubuntu image: SSH in and run the runcmd lines by hand

Anything that boots Ubuntu with cloud-init works. If your provider has no user-data field, SSH in and run the four runcmd lines.

Platforms and panels

Point any of these at the repo. They read the Dockerfile, build it, and run it. Two things to set everywhere: SESSION_SECRET, and a persistent volume on /data — without the volume your database disappears on the next deploy.

Coolify
New Resource → Docker Compose → point at the repo. Self-hosted PaaS on your own box
Dokploy
Create Application → Docker → repo URL. Add a volume mount for /data
Railway
Deploy from GitHub repo. Attach a volume at /data, set the port to 7000
Render
New Web Service → Docker. Add a persistent disk mounted at /data
Fly.io
fly launch reads the Dockerfile. Create a volume and mount it at /data
CapRover
One-click app from Dockerfile, with a persistent directory on /data
Portainer
Stacks → paste docker-compose.yml from the repo
Any Kubernetes
One image, one PVC on /data, one service on port 7000

First run

Open the address in a browser. A fresh install sends you straight to a setup form — admin account, site name, and one model. No config files to edit by hand.

The form asks for a token first. It is printed on first boot and written to $DATA_ROOT/setup.token. That is deliberate: without it, anyone who found a fresh box before you did could claim it as admin.

docker logs chathermes | grep -A2 "SETUP REQUIRED"
# or, without Docker:
cat data/setup.token

Finishing setup signs you in, deletes the token, and closes the form for good.

Once it is up

Check every service
./bin/health.sh
Stop everything
./bin/stop.sh
Re-run the env wizard
./bin/setup.sh
Verify a release bundle
./bin/verify-bundle.sh

The first account you create becomes the admin. Add your model providers under Admin → LLM, then set one as default — that is what new users get before they pick anything.