feat: add openclaw and hermes agent templates

This commit is contained in:
tiennm99 committed 2026-10-05 11:22:18 +07:00
1 parent 7616ff9f89
commit 8d4c3d14a4
7 files changed
+341

No files matched your search

+2
View File
@@ -82,8 +82,10 @@ Each links to its own README for variables, ports, and storage.
| [diun](diun/README.md) | Image-update notifier, reading the Docker API through a read-only proxy |
| [gitea-mirror](gitea-mirror/README.md) | Gitea + PostgreSQL + gitea-mirror, mirroring GitHub repos |
| [goclaw](goclaw/README.md) | Multi-tenant AI agent gateway, with pgvector PostgreSQL |
| [hermes](hermes/README.md) | Hermes Agent with its web chat UI |
| [litellm](litellm/README.md) | LiteLLM proxy in front of many LLM providers, with PostgreSQL and Redis |
| [open-webui](open-webui/README.md) | Open WebUI chat interface for OpenAI-compatible and Ollama providers |
| [openclaw](openclaw/README.md) | OpenClaw AI agent gateway, with a CDP browser |
| [opencode](opencode/README.md) | opencode coding agent, served as a browser UI |
| [owncloud](owncloud/README.md) | ownCloud file sync and share, with MariaDB and Redis |
| [paseo](paseo/README.md) | Paseo coding-agent daemon and web UI |
+15
View File
@@ -0,0 +1,15 @@
# Copy to .env and fill in. Never commit .env.
#
# cp .env.example .env
# Web UI login password.
# Generate one with: openssl rand -base64 24
HERMES_WEBUI_PASSWORD=
# Model provider for the agent.
OPENROUTER_API_KEY=
# Other providers. Uncomment here and in compose.yml to enable one.
# ANTHROPIC_API_KEY=
# OPENAI_API_KEY=
# GOOGLE_API_KEY=
+52
View File
@@ -0,0 +1,52 @@
# 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.
Two containers: `hermes-agent` runs the agent gateway, and `hermes-webui`
serves the chat on port `8787`.
## 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`.
Health check: `GET /health` on the web UI, also its compose healthcheck.
## Environment
| Variable | Default | Purpose |
| --- | --- | --- |
| `HERMES_WEBUI_PASSWORD` | — | Web UI login |
| `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.
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.
## 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 |
### Updating the agent
`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.
## Images
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.
+49
View File
@@ -0,0 +1,49 @@
services:
hermes-agent:
image: nousresearch/hermes-agent:latest
restart: unless-stopped
command: gateway run
environment:
- HERMES_HOME=/home/hermes/.hermes
- HERMES_UID=1000
- HERMES_GID=1000
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
# - 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-workspace:/workspace
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8787/health"]
interval: 30s
timeout: 5s
retries: 3
volumes:
hermes-home:
hermes-agent-src:
hermes-workspace:
+69
View File
@@ -0,0 +1,69 @@
# Copy to .env and fill in. Never commit .env.
#
# cp .env.example .env
# Web UI login.
# Generate a password with: openssl rand -base64 24
AUTH_USERNAME=admin
AUTH_PASSWORD=
# Token for the agent gateway. Generate one with: openssl rand -hex 32
OPENCLAW_GATEWAY_TOKEN=
# At least one provider key is required; OpenRouter is the active one.
OPENROUTER_API_KEY=
# Default model, e.g. openrouter/anthropic/claude-sonnet-4.5.
# OPENCLAW_PRIMARY_MODEL=
# Other providers. Uncomment here and in compose.yml to enable one.
# ANTHROPIC_API_KEY=
# OPENAI_API_KEY=
# GEMINI_API_KEY=
# XAI_API_KEY=
# GROQ_API_KEY=
# MISTRAL_API_KEY=
# CEREBRAS_API_KEY=
# VENICE_API_KEY=
# MOONSHOT_API_KEY=
# MOONSHOT_BASE_URL=https://api.moonshot.ai/v1
# KIMI_API_KEY=
# KIMI_BASE_URL=https://api.moonshot.ai/anthropic
# MINIMAX_API_KEY=
# ZAI_API_KEY=
# AI_GATEWAY_API_KEY=
# OPENCODE_API_KEY=
# SYNTHETIC_API_KEY=
# COPILOT_GITHUB_TOKEN=
# XIAOMI_API_KEY=
# Speech to text.
# DEEPGRAM_API_KEY=
# AWS Bedrock.
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# AWS_SESSION_TOKEN=
# AWS_REGION=us-east-1
# BEDROCK_PROVIDER_FILTER=anthropic
# OLLAMA_BASE_URL=
# Chat channels.
# TELEGRAM_BOT_TOKEN=
# DISCORD_BOT_TOKEN=
# SLACK_BOT_TOKEN=
# SLACK_APP_TOKEN=
# WHATSAPP_ENABLED=
# Gateway, browser and hook tuning.
# Origins allowed to open the control UI, comma separated, e.g. https://openclaw.example.com.
# OPENCLAW_ALLOWED_ORIGINS=
# OPENCLAW_GATEWAY_BIND=loopback
# BROWSER_DEFAULT_PROFILE=openclaw
# BROWSER_EVALUATE_ENABLED=true
# BROWSER_SNAPSHOT_MODE=efficient
# BROWSER_REMOTE_TIMEOUT_MS=1500
# BROWSER_REMOTE_HANDSHAKE_TIMEOUT_MS=3000
# HOOKS_ENABLED=false
# HOOKS_PATH=/hooks
# Extra apt packages installed into the container at start, space separated.
# OPENCLAW_DOCKER_APT_PACKAGES=
+65
View File
@@ -0,0 +1,65 @@
# openclaw
[OpenClaw](https://docs.openclaw.ai): a personal AI agent gateway with a web
UI, chat-channel bots and browser automation. Runs Coolify's
`coollabsio/openclaw` image, which wraps OpenClaw with nginx basic auth and
env-driven configuration.
Two containers: `openclaw`, and `browser`, a Chromium the agent drives over
the Chrome DevTools Protocol.
## Setup
1. Set `AUTH_PASSWORD`, `OPENCLAW_GATEWAY_TOKEN` and `OPENROUTER_API_KEY`.
2. Map the domain to port `8080` and deploy.
3. Open the domain and log in with `AUTH_USERNAME` / `AUTH_PASSWORD`.
Health check: `GET /healthz`, also the compose healthcheck.
## Environment
| Variable | Default | Purpose |
| --- | --- | --- |
| `AUTH_USERNAME` / `AUTH_PASSWORD` | `admin` / — | Basic-auth login in front of the web UI |
| `OPENCLAW_GATEWAY_TOKEN` | — | Token the web UI and clients use to reach the gateway |
| `OPENROUTER_API_KEY` | empty | Model provider |
| `OPENCLAW_PRIMARY_MODEL` | optional | Default model |
| Other provider keys, `AWS_*`, `OLLAMA_BASE_URL` | optional | Additional model providers |
| `TELEGRAM_BOT_TOKEN`, `DISCORD_BOT_TOKEN`, `SLACK_*`, `WHATSAPP_ENABLED` | optional | Chat channels |
| `OPENCLAW_ALLOWED_ORIGINS` | optional | Origins allowed to open the control UI |
| `BROWSER_*`, `HOOKS_*`, `OPENCLAW_GATEWAY_BIND` | optional | Tuning, defaults shown in `compose.yml` |
| `OPENCLAW_DOCKER_APT_PACKAGES` | optional | Extra apt packages installed at start |
`AUTH_PASSWORD` is required: without it nginx serves the UI with no login.
The entrypoint itself refuses to start without `OPENCLAW_GATEWAY_TOKEN` or
without at least one provider key.
OpenRouter stays active as the one provider every deployment needs; any
other provider is enabled by uncommenting its line. Each provider key is read
from the environment on every start, never stored in the config.
`PORT`, the gateway port, the state and workspace directories and
`BROWSER_CDP_URL` are fixed in `compose.yml`, as properties of this layout.
`OPENCLAW_CONFIG_JSON` sets `gateway.trustedProxies` to `127.0.0.1`. The
image's own nginx sits in front of the gateway on loopback, and current
OpenClaw (tested on 2026.9.8) rejects every proxied request with 403
`proxy_attribution_required` unless that proxy is trusted. The wrapper merges
this JSON into `openclaw.json` on every start.
The wrapper adds the deployment's domain to the control UI's allowed origins
from the `COOLIFY_URL` and `COOLIFY_FQDN` Coolify injects.
`OPENCLAW_ALLOWED_ORIGINS` is for any other origin, and for a deployment
Coolify does not inject that into.
## Storage
| Volume | Mount | Holds |
| --- | --- | --- |
| `openclaw-data` | `/data` | Config and sessions in `.openclaw`, the agent workspace in `workspace` |
| `browser-data` | `/config` | Chromium profile: cookies and logins of sites the agent uses |
## Images
Both images use `latest`. `coollabsio/openclaw` publishes no major tag, only
dated releases, so `latest` is the moving one.
+89
View File
@@ -0,0 +1,89 @@
services:
openclaw:
image: coollabsio/openclaw:latest
restart: unless-stopped
environment:
- AUTH_USERNAME=${AUTH_USERNAME:-admin}
- AUTH_PASSWORD=${AUTH_PASSWORD:?required}
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN:?required}
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
- PORT=8080
- OPENCLAW_GATEWAY_PORT=18789
- OPENCLAW_STATE_DIR=/data/.openclaw
- OPENCLAW_WORKSPACE_DIR=/data/workspace
- BROWSER_CDP_URL=http://browser:9223
- 'OPENCLAW_CONFIG_JSON={"gateway":{"trustedProxies":["127.0.0.1"]}}'
# - OPENCLAW_PRIMARY_MODEL=${OPENCLAW_PRIMARY_MODEL:-}
# - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
# - OPENAI_API_KEY=${OPENAI_API_KEY:-}
# - GEMINI_API_KEY=${GEMINI_API_KEY:-}
# - XAI_API_KEY=${XAI_API_KEY:-}
# - GROQ_API_KEY=${GROQ_API_KEY:-}
# - MISTRAL_API_KEY=${MISTRAL_API_KEY:-}
# - CEREBRAS_API_KEY=${CEREBRAS_API_KEY:-}
# - VENICE_API_KEY=${VENICE_API_KEY:-}
# - MOONSHOT_API_KEY=${MOONSHOT_API_KEY:-}
# - MOONSHOT_BASE_URL=${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}
# - KIMI_API_KEY=${KIMI_API_KEY:-}
# - KIMI_BASE_URL=${KIMI_BASE_URL:-https://api.moonshot.ai/anthropic}
# - MINIMAX_API_KEY=${MINIMAX_API_KEY:-}
# - ZAI_API_KEY=${ZAI_API_KEY:-}
# - AI_GATEWAY_API_KEY=${AI_GATEWAY_API_KEY:-}
# - OPENCODE_API_KEY=${OPENCODE_API_KEY:-}
# - SYNTHETIC_API_KEY=${SYNTHETIC_API_KEY:-}
# - COPILOT_GITHUB_TOKEN=${COPILOT_GITHUB_TOKEN:-}
# - XIAOMI_API_KEY=${XIAOMI_API_KEY:-}
# - DEEPGRAM_API_KEY=${DEEPGRAM_API_KEY:-}
# - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
# - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
# - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN:-}
# - AWS_REGION=${AWS_REGION:-us-east-1}
# - BEDROCK_PROVIDER_FILTER=${BEDROCK_PROVIDER_FILTER:-anthropic}
# - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-}
# - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
# - DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN:-}
# - SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN:-}
# - SLACK_APP_TOKEN=${SLACK_APP_TOKEN:-}
# - WHATSAPP_ENABLED=${WHATSAPP_ENABLED:-}
# - OPENCLAW_ALLOWED_ORIGINS=${OPENCLAW_ALLOWED_ORIGINS:-}
# - OPENCLAW_GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND:-loopback}
# - BROWSER_DEFAULT_PROFILE=${BROWSER_DEFAULT_PROFILE:-openclaw}
# - BROWSER_EVALUATE_ENABLED=${BROWSER_EVALUATE_ENABLED:-true}
# - BROWSER_SNAPSHOT_MODE=${BROWSER_SNAPSHOT_MODE:-efficient}
# - BROWSER_REMOTE_TIMEOUT_MS=${BROWSER_REMOTE_TIMEOUT_MS:-1500}
# - BROWSER_REMOTE_HANDSHAKE_TIMEOUT_MS=${BROWSER_REMOTE_HANDSHAKE_TIMEOUT_MS:-3000}
# - HOOKS_ENABLED=${HOOKS_ENABLED:-false}
# - HOOKS_PATH=${HOOKS_PATH:-/hooks}
# - OPENCLAW_DOCKER_APT_PACKAGES=${OPENCLAW_DOCKER_APT_PACKAGES:-}
volumes:
- openclaw-data:/data
depends_on:
browser:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-sf", "http://127.0.0.1:8080/healthz"]
interval: 10s
timeout: 10s
retries: 5
# Chromium the agent drives over CDP.
browser:
image: coollabsio/openclaw-browser:latest
restart: unless-stopped
shm_size: 2g
environment:
- PUID=1000
- PGID=1000
- CHROME_CLI=--remote-debugging-port=9222
- TZ=Etc/UTC
volumes:
- browser-data:/config
healthcheck:
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/9222' || exit 1"]
interval: 5s
timeout: 5s
retries: 10
volumes:
openclaw-data:
browser-data: