From 0d0a48221bce3799fc3ca265690ed14b235e44d5 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Mon, 5 Oct 2026 13:22:01 +0700 Subject: [PATCH] refactor: switch openclaw and hermes to their official images --- README.md | 4 +- hermes/.env.example | 11 +++-- hermes/Dockerfile | 4 ++ hermes/README.md | 74 +++++++++++++++++++------------ hermes/compose.yml | 43 ++++++------------ openclaw/.env.example | 40 +++++------------ openclaw/Dockerfile | 4 ++ openclaw/README.md | 99 +++++++++++++++++++++++++----------------- openclaw/compose.yml | 70 +++++++---------------------- openclaw/openclaw.json | 9 ++++ 10 files changed, 174 insertions(+), 184 deletions(-) create mode 100644 hermes/Dockerfile create mode 100644 openclaw/Dockerfile create mode 100644 openclaw/openclaw.json diff --git a/README.md b/README.md index 6170e55..54e6ea5 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/hermes/.env.example b/hermes/.env.example index 713152b..b1e0169 100644 --- a/hermes/.env.example +++ b/hermes/.env.example @@ -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= diff --git a/hermes/Dockerfile b/hermes/Dockerfile new file mode 100644 index 0000000..4e2cf24 --- /dev/null +++ b/hermes/Dockerfile @@ -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 diff --git a/hermes/README.md b/hermes/README.md index 8bbafa7..d131070 100644 --- a/hermes/README.md +++ b/hermes/README.md @@ -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. diff --git a/hermes/compose.yml b/hermes/compose.yml index 61b6b62..07d28de 100644 --- a/hermes/compose.yml +++ b/hermes/compose.yml @@ -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: diff --git a/openclaw/.env.example b/openclaw/.env.example index c94cc99..87eb712 100644 --- a/openclaw/.env.example +++ b/openclaw/.env.example @@ -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= diff --git a/openclaw/Dockerfile b/openclaw/Dockerfile new file mode 100644 index 0000000..186ab4b --- /dev/null +++ b/openclaw/Dockerfile @@ -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 diff --git a/openclaw/README.md b/openclaw/README.md index 9e62bab..00fc299 100644 --- a/openclaw/README.md +++ b/openclaw/README.md @@ -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. diff --git a/openclaw/compose.yml b/openclaw/compose.yml index 585856f..0cdb69a 100644 --- a/openclaw/compose.yml +++ b/openclaw/compose.yml @@ -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: diff --git a/openclaw/openclaw.json b/openclaw/openclaw.json new file mode 100644 index 0000000..0d1bd13 --- /dev/null +++ b/openclaw/openclaw.json @@ -0,0 +1,9 @@ +{ + "gateway": { + "mode": "local", + "bind": "lan", + "port": 18789, + "publicOrigin": "${OPENCLAW_PUBLIC_ORIGIN}", + "trustedProxies": ["${OPENCLAW_TRUSTED_PROXIES}"] + } +}