mirror of
https://github.com/tiennm99/composes.git
synced 2026-10-18 02:14:34 +00:00
refactor: switch openclaw and hermes to their official images
This commit is contained in:
1 parent
8d4c3d14a4
commit
0d0a48221b
10 files changed
+174
-184
No files matched your search
+8
-3
@@ -2,9 +2,14 @@
|
||||
#
|
||||
# cp .env.example .env
|
||||
|
||||
# Web UI login password.
|
||||
# Generate one with: openssl rand -base64 24
|
||||
HERMES_WEBUI_PASSWORD=
|
||||
# Full public URL of the dashboard, e.g. https://hermes.example.com.
|
||||
HERMES_DASHBOARD_PUBLIC_URL=https://hermes.example.com
|
||||
|
||||
# Dashboard login. Generate the password with: openssl rand -base64 24
|
||||
HERMES_DASHBOARD_USERNAME=hermes
|
||||
HERMES_DASHBOARD_PASSWORD=
|
||||
# Signs dashboard sessions; keep it stable. Generate with: openssl rand -hex 32
|
||||
HERMES_DASHBOARD_SECRET=
|
||||
|
||||
# Model provider for the agent.
|
||||
OPENROUTER_API_KEY=
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
FROM nousresearch/hermes-agent:latest
|
||||
|
||||
# Workspace directory owned by the hermes user (HERMES_UID/HERMES_GID 1000).
|
||||
RUN mkdir -p /workspace && chown 1000:1000 /workspace
|
||||
+47
-27
@@ -1,52 +1,72 @@
|
||||
# hermes
|
||||
|
||||
[Hermes Agent](https://github.com/NousResearch/hermes-agent), an autonomous AI
|
||||
agent with persistent memory and scheduling, behind
|
||||
[Hermes WebUI](https://github.com/nesquena/hermes-webui), a self-hosted web
|
||||
chat for it.
|
||||
[Hermes Agent](https://github.com/NousResearch/hermes-agent): an autonomous AI
|
||||
agent with persistent memory, scheduling and chat-platform gateways, from Nous
|
||||
Research's official image, with its built-in web dashboard.
|
||||
|
||||
Two containers: `hermes-agent` runs the agent gateway, and `hermes-webui`
|
||||
serves the chat on port `8787`.
|
||||
One container. `gateway run` starts the agent gateway, and the image's s6
|
||||
supervisor also starts the dashboard on port `9119`: chat (the Hermes
|
||||
terminal UI in the browser), sessions, config, cron, skills and logs.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Set `HERMES_WEBUI_PASSWORD` and `OPENROUTER_API_KEY`.
|
||||
2. Map the domain to the `hermes-webui` container on port `8787` and deploy.
|
||||
3. Open the domain and log in with `HERMES_WEBUI_PASSWORD`.
|
||||
1. Set `HERMES_DASHBOARD_PUBLIC_URL`, `HERMES_DASHBOARD_PASSWORD`,
|
||||
`HERMES_DASHBOARD_SECRET` and `OPENROUTER_API_KEY`.
|
||||
2. Map the domain to port `9119` and deploy.
|
||||
3. Open the domain and log in with `HERMES_DASHBOARD_USERNAME` /
|
||||
`HERMES_DASHBOARD_PASSWORD`.
|
||||
|
||||
Health check: `GET /health` on the web UI, also its compose healthcheck.
|
||||
Health check: `GET /api/status`, also the compose healthcheck.
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `HERMES_WEBUI_PASSWORD` | — | Web UI login |
|
||||
| `HERMES_DASHBOARD_PUBLIC_URL` | — | Full public URL, e.g. `https://hermes.example.com` |
|
||||
| `HERMES_DASHBOARD_USERNAME` / `HERMES_DASHBOARD_PASSWORD` | `hermes` / — | Dashboard login |
|
||||
| `HERMES_DASHBOARD_SECRET` | — | Signs dashboard sessions |
|
||||
| `OPENROUTER_API_KEY` | empty | Model provider |
|
||||
| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY` | optional | Other model providers |
|
||||
|
||||
`HERMES_WEBUI_PASSWORD` is required: without it the chat, and the agent
|
||||
behind it, are open to anyone who reaches the domain.
|
||||
`HERMES_DASHBOARD=1` turns the dashboard on. Bound to `0.0.0.0`, it refuses to
|
||||
start without an auth provider, so the password is required. The image's
|
||||
username/password provider is the one that needs no outside identity service;
|
||||
upstream describes it as meant for trusted networks and recommends OAuth (Nous
|
||||
Portal) or self-hosted OIDC for a public domain.
|
||||
|
||||
The uid/gid pairs are pinned to `1000` in `compose.yml`. Both containers write
|
||||
the shared `hermes-home` volume, so both must run as the same user.
|
||||
`HERMES_DASHBOARD_PUBLIC_URL` adds the domain to the dashboard's Host and
|
||||
WebSocket Origin guard, which rejects requests for any other host.
|
||||
|
||||
`HERMES_DASHBOARD_SECRET` keeps sessions valid across restarts; without it
|
||||
each restart signs with a new random key and logs everyone out.
|
||||
|
||||
The uid/gid are pinned to `1000` in `compose.yml`; the `Dockerfile` depends on
|
||||
that (see Storage).
|
||||
|
||||
## Storage
|
||||
|
||||
| Volume | Mount | Holds |
|
||||
| --- | --- | --- |
|
||||
| `hermes-home` | `/home/hermes/.hermes` (agent), `/home/hermeswebui/.hermes` (web UI) | Agent config, memory, skills and sessions; web UI state in `webui/` |
|
||||
| `hermes-agent-src` | `/opt/hermes` (agent), `.hermes/hermes-agent`, read-only (web UI) | The agent's source code, which the web UI imports |
|
||||
| `hermes-workspace` | `/workspace` (web UI) | Files the agent works on |
|
||||
| `hermes-data` | `/opt/data` | `HERMES_HOME`: config, `.env`, sessions, memory, skills, logs |
|
||||
| `hermes-workspace` | `/workspace` | Files the agent works on |
|
||||
|
||||
### Updating the agent
|
||||
The image hard-blocks the agent's file tools from writing outside
|
||||
`HERMES_WRITE_SAFE_ROOT`, which it sets to `/opt/data` alone, so
|
||||
`compose.yml` adds `/workspace` to it. `TERMINAL_CWD` starts gateway and cron
|
||||
terminal sessions in `/workspace`. Upstream marks that variable deprecated in
|
||||
favour of `terminal.cwd` in `config.yaml`; it is used here so the setting stays
|
||||
in the compose file rather than on the volume.
|
||||
|
||||
`hermes-agent-src` is filled from the agent image only when the volume is
|
||||
first created. A newer `latest` image therefore keeps running the old source
|
||||
until the volume is removed, which upstream documents as the upgrade step:
|
||||
stop the app, delete the `hermes-agent-src` volume, and deploy again. Nothing
|
||||
else lives in that volume.
|
||||
The `Dockerfile` exists only to make `/workspace` writable. The image does not
|
||||
ship that directory and its init chowns only `/opt/data`, so a named volume on
|
||||
`/workspace` would come up `root:root`. Creating the directory in the image,
|
||||
owned by `1000:1000`, fixes that: Docker seeds an empty named volume from the
|
||||
image directory, ownership included.
|
||||
|
||||
## Images
|
||||
## Image
|
||||
|
||||
Both images use `latest`. Upstream recommends moving the two together, since
|
||||
the web UI imports the agent's source and is built against matching versions.
|
||||
`nousresearch/hermes-agent:latest` moves only on stable releases, roughly
|
||||
weekly; upstream publishes no major tag. The agent's code lives in the image,
|
||||
not a volume, so a new release takes effect on the next pull and recreate. The
|
||||
first start after an upgrade migrates `config.yaml`, keeping a timestamped
|
||||
backup.
|
||||
+13
-30
@@ -1,49 +1,32 @@
|
||||
services:
|
||||
hermes-agent:
|
||||
image: nousresearch/hermes-agent:latest
|
||||
hermes:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
command: gateway run
|
||||
environment:
|
||||
- HERMES_HOME=/home/hermes/.hermes
|
||||
- HERMES_DASHBOARD=1
|
||||
- HERMES_DASHBOARD_PUBLIC_URL=${HERMES_DASHBOARD_PUBLIC_URL:?required}
|
||||
- HERMES_DASHBOARD_BASIC_AUTH_USERNAME=${HERMES_DASHBOARD_USERNAME:-hermes}
|
||||
- HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=${HERMES_DASHBOARD_PASSWORD:?required}
|
||||
- HERMES_DASHBOARD_BASIC_AUTH_SECRET=${HERMES_DASHBOARD_SECRET:?required}
|
||||
- HERMES_UID=1000
|
||||
- HERMES_GID=1000
|
||||
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
|
||||
- HERMES_WRITE_SAFE_ROOT=/opt/data:/workspace
|
||||
- TERMINAL_CWD=/workspace
|
||||
# - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
||||
# - OPENAI_API_KEY=${OPENAI_API_KEY:-}
|
||||
# - GOOGLE_API_KEY=${GOOGLE_API_KEY:-}
|
||||
volumes:
|
||||
- hermes-home:/home/hermes/.hermes
|
||||
- hermes-agent-src:/opt/hermes
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "test -d /home/hermes/.hermes || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Web chat UI, sharing the agent's home and source.
|
||||
hermes-webui:
|
||||
image: ghcr.io/nesquena/hermes-webui:latest
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- hermes-agent
|
||||
environment:
|
||||
- HERMES_WEBUI_PASSWORD=${HERMES_WEBUI_PASSWORD:?required}
|
||||
- WANTED_UID=1000
|
||||
- WANTED_GID=1000
|
||||
- HERMES_WEBUI_HOST=0.0.0.0
|
||||
- HERMES_WEBUI_PORT=8787
|
||||
- HERMES_WEBUI_STATE_DIR=/home/hermeswebui/.hermes/webui
|
||||
volumes:
|
||||
- hermes-home:/home/hermeswebui/.hermes
|
||||
- hermes-agent-src:/home/hermeswebui/.hermes/hermes-agent:ro
|
||||
- hermes-data:/opt/data
|
||||
- hermes-workspace:/workspace
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:8787/health"]
|
||||
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:9119/api/status"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
volumes:
|
||||
hermes-home:
|
||||
hermes-agent-src:
|
||||
hermes-data:
|
||||
hermes-workspace:
|
||||
Reference in new issue
Block a user