mirror of
https://github.com/tiennm99/composes.git
synced 2026-10-11 03:13:16 +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
@@ -82,10 +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 |
|
||||
| [hermes](hermes/README.md) | Hermes Agent with its built-in web dashboard |
|
||||
| [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 |
|
||||
| [openclaw](openclaw/README.md) | OpenClaw AI agent gateway, with built-in browser automation |
|
||||
| [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 |
|
||||
|
||||
+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:
|
||||
+11
-29
@@ -2,19 +2,20 @@
|
||||
#
|
||||
# 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
|
||||
# Gateway token: the Control UI login and the key for every API and WebSocket call.
|
||||
# Generate one with: openssl rand -hex 32
|
||||
OPENCLAW_GATEWAY_TOKEN=
|
||||
|
||||
# At least one provider key is required; OpenRouter is the active one.
|
||||
# Public origin of the Control UI, scheme included, no trailing slash.
|
||||
OPENCLAW_PUBLIC_ORIGIN=https://openclaw.example.com
|
||||
|
||||
# Address range the reverse proxy connects from, in CIDR form.
|
||||
OPENCLAW_TRUSTED_PROXIES=10.0.0.0/16
|
||||
|
||||
# At least one model provider; OpenRouter is the active one.
|
||||
OPENROUTER_API_KEY=
|
||||
|
||||
# Default model, e.g. openrouter/anthropic/claude-sonnet-4.5.
|
||||
# OPENCLAW_PRIMARY_MODEL=
|
||||
TZ=Asia/Ho_Chi_Minh
|
||||
|
||||
# Other providers. Uncomment here and in compose.yml to enable one.
|
||||
# ANTHROPIC_API_KEY=
|
||||
@@ -26,9 +27,7 @@ OPENROUTER_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=
|
||||
@@ -36,6 +35,7 @@ OPENROUTER_API_KEY=
|
||||
# SYNTHETIC_API_KEY=
|
||||
# COPILOT_GITHUB_TOKEN=
|
||||
# XIAOMI_API_KEY=
|
||||
# OLLAMA_API_KEY=
|
||||
# Speech to text.
|
||||
# DEEPGRAM_API_KEY=
|
||||
# AWS Bedrock.
|
||||
@@ -43,27 +43,9 @@ OPENROUTER_API_KEY=
|
||||
# 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=
|
||||
@@ -0,0 +1,4 @@
|
||||
FROM ghcr.io/openclaw/openclaw:latest-browser
|
||||
|
||||
# Gateway config seeded into the state volume on first start.
|
||||
COPY --chown=node:node openclaw.json /home/node/.openclaw/openclaw.json
|
||||
+60
-39
@@ -1,65 +1,86 @@
|
||||
# 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.
|
||||
Control UI, chat-channel bots and browser automation. Runs the project's
|
||||
official image, in its `-browser` variant with Chromium built in.
|
||||
|
||||
Two containers: `openclaw`, and `browser`, a Chromium the agent drives over
|
||||
the Chrome DevTools Protocol.
|
||||
One container, serving the gateway and the Control UI on port `18789`.
|
||||
|
||||
## 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`.
|
||||
1. Set `OPENCLAW_GATEWAY_TOKEN`, `OPENCLAW_PUBLIC_ORIGIN` and
|
||||
`OPENROUTER_API_KEY`.
|
||||
2. Map the domain to port `18789` and deploy.
|
||||
3. Open the domain and connect with the gateway token. Each new browser is
|
||||
then approved once from inside the container:
|
||||
`node openclaw.mjs devices approve`.
|
||||
4. Pick a default model in the Control UI. The image's default is an OpenAI
|
||||
model, which needs `OPENAI_API_KEY`.
|
||||
|
||||
Health check: `GET /healthz`, also the compose healthcheck.
|
||||
Health check: the image's own, which calls `/healthz`.
|
||||
|
||||
## 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 |
|
||||
| `OPENCLAW_GATEWAY_TOKEN` | — | Control UI login and API/WebSocket key |
|
||||
| `OPENCLAW_PUBLIC_ORIGIN` | — | Public origin, e.g. `https://openclaw.example.com` |
|
||||
| `OPENCLAW_TRUSTED_PROXIES` | `10.0.0.0/16` | Range the reverse proxy connects from |
|
||||
| `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 |
|
||||
| `TZ` | `Asia/Ho_Chi_Minh` | Timezone for logs and schedules |
|
||||
| Other provider keys, `AWS_*` | optional | Additional model providers |
|
||||
| `TELEGRAM_BOT_TOKEN`, `DISCORD_BOT_TOKEN`, `SLACK_*` | optional | Chat channels |
|
||||
|
||||
`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.
|
||||
`OPENCLAW_GATEWAY_TOKEN` is required: the gateway binds to all interfaces, and
|
||||
the token is what keeps the Control UI and API closed. Provider and channel
|
||||
keys are read from the environment, so the provider set is changed by
|
||||
uncommenting lines.
|
||||
|
||||
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.
|
||||
`OPENCLAW_TRUSTED_PROXIES` must cover the address Coolify's Traefik connects
|
||||
from. Traefik joins each app's network with an address from the Docker
|
||||
address pool, which on this host is `10.0.0.0/16` in `/24` slices; the gateway
|
||||
answers every proxied request from an untrusted address with 403
|
||||
`proxy_attribution_required`.
|
||||
|
||||
`PORT`, the gateway port, the state and workspace directories and
|
||||
`BROWSER_CDP_URL` are fixed in `compose.yml`, as properties of this layout.
|
||||
## Config
|
||||
|
||||
`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 rest of OpenClaw's settings live in `openclaw.json` on the state volume
|
||||
and are edited in the Control UI or with `node openclaw.mjs config set`.
|
||||
|
||||
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.
|
||||
The `Dockerfile` copies `openclaw.json` into the image's state directory, and
|
||||
Docker seeds an empty named volume from it on first start. It holds only what
|
||||
this deployment needs before anyone can log in: local gateway mode, a bind to
|
||||
all interfaces, the port, and the public origin and trusted proxy range as
|
||||
`${VAR}` references that OpenClaw resolves from the environment at load. The
|
||||
image's own start-up `doctor --fix` keeps those references when it rewrites
|
||||
the file. Without `gateway.mode` a fresh volume crash-loops.
|
||||
|
||||
The seed applies only to a fresh volume. Editing `openclaw.json` in the
|
||||
repository later changes nothing for an existing deployment; change the live
|
||||
config instead.
|
||||
|
||||
## 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 |
|
||||
| `openclaw-state` | `/home/node/.openclaw` | `openclaw.json`, sessions, credentials, agent state |
|
||||
| `openclaw-workspace` | `/home/node/.openclaw/workspace` | Files the agent works on |
|
||||
| `openclaw-secrets` | `/home/node/.config/openclaw` | Auth-profile secrets |
|
||||
|
||||
## Images
|
||||
The three mounts follow upstream's own compose. `/home/node` as a whole is not
|
||||
mounted: the bundled Chromium lives in `/home/node/.cache`, and a volume there
|
||||
would freeze it at the first image's version.
|
||||
|
||||
Both images use `latest`. `coollabsio/openclaw` publishes no major tag, only
|
||||
dated releases, so `latest` is the moving one.
|
||||
`cap_drop` and `no-new-privileges` are also upstream's; the image runs as the
|
||||
non-root `node` user.
|
||||
|
||||
## Image
|
||||
|
||||
`ghcr.io/openclaw/openclaw:latest-browser` is the latest stable release with
|
||||
Playwright Chromium built in, published by the project's release automation.
|
||||
Upstream publishes no major tag.
|
||||
|
||||
On ARM64, release 2026.9.8 cannot find its bundled Chromium ("No supported
|
||||
browser found"); the fix is merged upstream but not yet released. Everything
|
||||
except browser automation works meanwhile, and the browser starts working on
|
||||
the first pull after a release that contains the fix, with no change here.
|
||||
+16
-54
@@ -1,19 +1,13 @@
|
||||
services:
|
||||
openclaw:
|
||||
image: coollabsio/openclaw:latest
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- AUTH_USERNAME=${AUTH_USERNAME:-admin}
|
||||
- AUTH_PASSWORD=${AUTH_PASSWORD:?required}
|
||||
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN:?required}
|
||||
- OPENCLAW_PUBLIC_ORIGIN=${OPENCLAW_PUBLIC_ORIGIN:?required}
|
||||
- OPENCLAW_TRUSTED_PROXIES=${OPENCLAW_TRUSTED_PROXIES:-10.0.0.0/16}
|
||||
- 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:-}
|
||||
- TZ=${TZ:-Asia/Ho_Chi_Minh}
|
||||
# - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
||||
# - OPENAI_API_KEY=${OPENAI_API_KEY:-}
|
||||
# - GEMINI_API_KEY=${GEMINI_API_KEY:-}
|
||||
@@ -23,9 +17,7 @@ services:
|
||||
# - 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:-}
|
||||
@@ -33,57 +25,27 @@ services:
|
||||
# - SYNTHETIC_API_KEY=${SYNTHETIC_API_KEY:-}
|
||||
# - COPILOT_GITHUB_TOKEN=${COPILOT_GITHUB_TOKEN:-}
|
||||
# - XIAOMI_API_KEY=${XIAOMI_API_KEY:-}
|
||||
# - OLLAMA_API_KEY=${OLLAMA_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
|
||||
- openclaw-state:/home/node/.openclaw
|
||||
- openclaw-workspace:/home/node/.openclaw/workspace
|
||||
- openclaw-secrets:/home/node/.config/openclaw
|
||||
cap_drop:
|
||||
- NET_RAW
|
||||
- NET_ADMIN
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
volumes:
|
||||
openclaw-data:
|
||||
browser-data:
|
||||
openclaw-state:
|
||||
openclaw-workspace:
|
||||
openclaw-secrets:
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"bind": "lan",
|
||||
"port": 18789,
|
||||
"publicOrigin": "${OPENCLAW_PUBLIC_ORIGIN}",
|
||||
"trustedProxies": ["${OPENCLAW_TRUSTED_PROXIES}"]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user