OpenClaw can be deployed with Docker Compose so that the gateway, optional CLI, and optional web search backend run as separate containers but share the same persistent data directory.

What This Setup Does

This deployment defines four services:

  • openclaw-gateway: the main OpenClaw service
  • socat-proxy: exposes the internal gateway port for external access
  • openclaw-cli: an on-demand CLI container using the same OpenClaw state
  • searxng: an optional self-hosted metasearch backend

The persistent data is stored under /home/jerry/openclaw.

Prerequisites

  • Docker and Docker Compose plugin installed
  • A writable host directory such as /home/jerry/openclaw
  • A .env file containing the environment variables required by OpenClaw

Check Docker first:

docker --version
docker compose version

Prepare Directories

Create the directories used by the containers:

mkdir -p /home/jerry/openclaw/workspace
mkdir -p /home/jerry/openclaw/searxng

These mounts are used as follows:

  • /home/jerry/openclaw: OpenClaw configuration and state
  • /home/jerry/openclaw/workspace: working files created by OpenClaw
  • /home/jerry/openclaw/searxng: SearXNG configuration

Compose File

Save the following as docker-compose.yml:

services:
  openclaw-gateway:
    image: ghcr.io/phioranex/openclaw-docker:latest
    container_name: openclaw-gateway
    restart: unless-stopped
    stdin_open: true
    tty: true
    # Uncomment the following line if running on Synology NAS or other systems with UID/GID issues
    user: "9003:1003"
    volumes:
      - /home/jerry/openclaw:/home/node/.openclaw
      - /home/jerry/openclaw/workspace:/home/node/.openclaw/workspace
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "18789:18789"
      - "18790:18790"
    environment:
      - HOME=/home/node
      - NODE_ENV=production
      - OPENCLAW_SKIP_SERVICE_CHECK=true
      - TZ=Asia/Singapore
    env_file:
      - .env
    command: ["gateway"]
  
  socat-proxy:
    image: alpine/socat
    container_name: openclaw-socat
    restart: unless-stopped
    network_mode: "service:openclaw-gateway"
    command: "TCP-LISTEN:18790,fork,bind=0.0.0.0,reuseaddr TCP:127.0.0.1:18789"
 
  openclaw-cli:
    image: ghcr.io/phioranex/openclaw-docker:latest
    container_name: openclaw-cli
    stdin_open: true
    tty: true
    # Uncomment the following line if running on Synology NAS or other systems with UID/GID issues
    user: "9003:1003"
    volumes:
      - /home/jerry/openclaw:/home/node/.openclaw
      - /home/jerry/openclaw/workspace:/home/node/.openclaw/workspace
    environment:
      - HOME=/home/node
      - NODE_ENV=production
    entrypoint: ["node", "/app/dist/index.js"]
    profiles:
      - cli
 
  searxng:
    image: searxng/searxng:latest
    container_name: searxng
    ports:
      - "8081:8081"
    volumes:
      - /home/jerry/openclaw/searxng:/etc/searxng
    environment:
      - SEARXNG_BASE_URL=http://localhost:8081/
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
      - DAC_OVERRIDE
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"

Note

The compose example keeps user: "9003:1003" enabled. Change it to your own host UID:GID, or remove it entirely if you do not need explicit user mapping.

Environment File

Create a .env file in the same directory as docker-compose.yml.

touch .env

Put the OpenClaw-specific secrets and runtime configuration in this file. Do not commit .env into Git.

Add a Telegram Bot

Telegram is one of the simplest ways to access OpenClaw remotely.

1. Create a bot with BotFather

In Telegram, open @BotFather and create a new bot:

/newbot

BotFather will return a bot token in the form:

1234567890:ABCdefGHIjklMNOpqrsTUVwxyz

Keep this token private.

2. Add the bot token to .env

Add the Telegram token to your .env file:

TELEGRAM_BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz

According to the OpenClaw Telegram docs, TELEGRAM_BOT_TOKEN works as the environment-variable fallback for the default account.

3. Optional: add Telegram channel config

If you want explicit Telegram channel settings instead of relying only on the environment variable, add a Telegram section in your OpenClaw config under the mounted OpenClaw data directory.

Example:

{
  "channels": {
    "telegram": {
      "enabled": true,
      "botToken": "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",
      "dmPolicy": "pairing",
      "groups": {
        "*": {
          "requireMention": true
        }
      }
    }
  }
}

Recommended defaults:

  • dmPolicy: "pairing" so random users cannot immediately access the bot
  • requireMention: true in groups so the bot only responds when explicitly mentioned

4. Restart the gateway

After updating .env or the OpenClaw config, restart the containers:

docker compose up -d
docker compose logs -f openclaw-gateway

5. Pair your Telegram account

After the gateway is running, send a direct message to your bot in Telegram.

Then use the CLI container to list pending Telegram pairing requests:

docker compose run --rm --profile cli openclaw-cli pairing list telegram

Approve the pairing code:

docker compose run --rm --profile cli openclaw-cli pairing approve telegram <CODE>

This is the safest default setup for personal use.

6. Optional: use the bot in group chats

If you want the bot to work in a Telegram group:

  • add the bot to the group
  • keep requireMention: true unless you really want it replying to all messages
  • if the bot needs to read all group messages, disable BotFather privacy mode with /setprivacy or make the bot a group admin

If you change privacy mode, remove and re-add the bot to the group so Telegram applies the new behavior.

Start the Services

Launch the gateway and SearXNG in the background:

docker compose up -d

Check status:

docker compose ps
docker compose logs -f openclaw-gateway

Access and Verify

After startup, the main exposed ports are:

  • 18789: OpenClaw gateway
  • 18790: forwarded by socat-proxy
  • 8081: SearXNG

Verify the containers are running:

docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

If the gateway does not start, check:

  • the .env file exists and is complete
  • the mounted directories are writable
  • the user: "9003:1003" mapping matches your host permissions, or remove it and retry

Run the CLI Container

The CLI service is in the cli profile, so it does not start by default.

Run it when needed:

docker compose run --rm --profile cli openclaw-cli --help

Because the CLI shares /home/node/.openclaw, it uses the same configuration and workspace as the gateway container.

Update the Deployment

Pull the latest images and recreate the services:

docker compose pull
docker compose up -d

Stop or Remove

Stop the stack:

docker compose stop

Remove containers while keeping data:

docker compose down

Notes

  • Keep /home/jerry/openclaw backed up if the workspace or configuration matters.
  • searxng is optional. Remove that service if you do not need a local search backend.
  • If this is exposed outside your local machine, put it behind a reverse proxy and access control instead of publishing the ports directly.
  • Telegram references:
  • AI Tools - Return to the AI tools overview
  • Claude Code - Terminal-based coding assistant workflow
  • Docker - General Docker usage notes