This post will walk you through how to set up Openclaw in Docker with Azure Foundry and the Responses API.

Azure AI Foundry allows you to play around with many different models, but keep in mind you cannot set hard spend limits, so be sure to create a budget alert at the very least.

The responses API is important because then we can set things like reasoning effort.

Docker Network

If you want, create a docker network (bridge mode) just to contain your Openclaw. This is useful if you are running other containers on the same host just to isolate things a bit.

Docker Compose

Here is my docker compose:

services:
  openclaw-gateway:
    image: ${OPENCLAW_IMAGE:-ghcr.io/openclaw/openclaw:latest}
    env_file:
      - .env
    networks:
      - openclaw_network
    environment:
      HOME: /home/node
      OPENCLAW_HOME: /home/node
      TERM: xterm-256color
      OPENCLAW_STATE_DIR: /home/node/.openclaw
      OPENCLAW_CONFIG_PATH: /home/node/.openclaw/openclaw.json
      OPENCLAW_CONFIG_DIR: /home/node/.openclaw
      OPENCLAW_WORKSPACE_DIR: /home/node/.openclaw/workspace
    volumes:
      - ./data:/home/node/.openclaw
      - ./workspace:/home/node/.openclaw/workspace
      - ./secrets:/home/node/.config/openclaw
      # Uncomment if running Docker-in-Docker sandboxing:
      # - /var/run/docker.sock:/var/run/docker.sock
    cap_drop:
      - NET_RAW
      - NET_ADMIN
    security_opt:
      - no-new-privileges:true
    extra_hosts:
      - "host.docker.internal:host-gateway"
    ports:
      - "${OPENCLAW_GATEWAY_PORT:-18789}:18789"
      - "${OPENCLAW_BRIDGE_PORT:-18790}:18790"
      - "${OPENCLAW_MSTEAMS_PORT:-3978}:3978"
    init: true
    restart: unless-stopped
    command:
      [
        "node",
        "dist/index.js",
        "gateway",
        "--bind",
        "${OPENCLAW_GATEWAY_BIND:-lan}",
        "--port",
        "18789",
      ]
    healthcheck:
      test:
        [
          "CMD",
          "node",
          "-e",
          "fetch('http://127.0.0.1:18789/healthz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
        ]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 20s
      

  openclaw-cli:
    image: ${OPENCLAW_IMAGE:-ghcr.io/openclaw/openclaw:latest}
    network_mode: "service:openclaw-gateway"
    env_file:
      - .env
    # Not needed because network_mode is defined, which piggybacks this container on the gw container
    #networks:
    #  - openclaw_network
    cap_drop:
      - NET_RAW
      - NET_ADMIN
    security_opt:
      - no-new-privileges:true
    environment:
      HOME: /home/node
      OPENCLAW_HOME: /home/node
      TERM: xterm-256color
      OPENCLAW_STATE_DIR: /home/node/.openclaw
      OPENCLAW_CONFIG_PATH: /home/node/.openclaw/openclaw.json
      OPENCLAW_CONFIG_DIR: /home/node/.openclaw
      OPENCLAW_WORKSPACE_DIR: /home/node/.openclaw/workspace
      BROWSER: echo
    volumes:
      - ./data:/home/node/.openclaw
      - ./workspace:/home/node/.openclaw/workspace
      - ./secrets:/home/node/.config/openclaw
    stdin_open: true
    tty: true
    init: true
    entrypoint: ["node", "dist/index.js"]
    depends_on:
      - openclaw-gateway
      
networks:
  openclaw_network:
    external: true

Docker env File

# Image & Ports
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw:latest
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_MSTEAMS_PORT=3978
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_TZ=Africa/Johannesburg

# Gateway Security & Tokens
OPENCLAW_GATEWAY_TOKEN=xxx
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=
OPENCLAW_DISABLE_BONJOUR=1

# -----------------------------------------------------------------------------
# LLM Provider API Keys
# -----------------------------------------------------------------------------
MICROSOFT_FOUNDRY_API_KEY=xxx
OPENAI_API_KEY=sk-proj-xxx
GEMINI_API_KEY=xxx

# OpenTelemetry Monitoring (Optional)
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=openclaw
OTEL_SEMCONV_STABILITY_OPT_IN=
OPENCLAW_OTEL_PRELOADED=

Start the Stack (compose up)

You will most likely get an “EACCES” error. To fix it, do this:

Be in your Openclaw directory where it creates the data, workspace, and secrets folder. Here is mine:

Openclaw folders it created when you started the compose file
# 1. Stop the stack first
docker compose down

Then cd into the directory where the folders are that the openclaw container created
# 2. Grant ownership of your local mount folders to UID 1000 (container's node user)
sudo chown -R 1000:1000 ./data ./workspace ./secrets

# 3. Ensure read/write/execute permissions are set for the owner
chmod -R 755 ./data ./workspace ./secrets

# 4. Bring the stack back up
docker compose up -d

Then you need to create a minimal config file, otherwhise your Openclaw will throw this error: Missing config. Run openclaw setup or set gateway.mode=local (or pass –allow-unconfigured).

Create this in ./data/openclaw.json

{
  "gateway": {
    "mode": "local",
    "bind": "lan",
    "port": 18789,
    "trustedProxies": [
      "172.21.0.0/16"
    ],
    "controlUi": {
      "allowedOrigins": [
        "https://openclaw.internal.leighonline.net"
      ]
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "primary": "microsoft-foundry/gpt-5.6-xxx-xxx",
        "fallbacks": [
          "openai/gpt-5.6-luna",
          "google/gemini-flash-latest"
        ]
      }
    }
  },
  "plugins": {
    "entries": {
      "canvas": {
        "enabled": true,
        "config": {
          "host": {
            "root": "~/.openclaw/workspace/canvas"
          }
        }
      }
    }
  },
  "meta": {
    "lastTouchedVersion": "2026.7.1",
    "lastTouchedAt": "2026-08-02T05:55:49.213Z"
  },
  "models": {
    "pricing": {
      "enabled": true
    },
    "providers": {
      "microsoft-foundry": {
        "baseUrl": "https://<foundry-url>.services.ai.azure.com/openai/v1",
        "apiKey": "${MICROSOFT_FOUNDRY_API_KEY}",
        "api": "openai-responses",
        "authHeader": false,
        "headers": {
          "api-key": "${MICROSOFT_FOUNDRY_API_KEY}"
        }
      }
    }
  }
}

Then change permissions “sudo chown 1000:1000 ./data/openclaw.json“

What the Proxies and AllowedOrigin config does

  • TrustedProxies section: This is your openclaw docker network range. Add it in there so that Openclaw knows this is you when connecting from your web browser.
  • AllowedOrigins section: This is needed if you want to access Openclaw via HTTPS later on. We need to add this for its CORS to allow our custom domain.

Fix permissions of the file just in case “sudo chown 1000:1000 ./data/openclaw.json“

Openclaw HTTPS

To access Openclaw over HTTPS I will just be using my existing NGINX Proxy manager and attach it to my Openclaw network

services:
  nginxproxymanager:
    container_name: nginxproxymanager
    networks:
      - internal_proxy
      - openclaw_network
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      #- '80:80'    # Public HTTP Port. Not needed because NPM has an entry for iteself mapped to port 81 
      - '443:443'  # Public HTTPS Port
      - '81'
      #- '81:81'    # Admin Web Port. Not needed because NPM has an entry for iteself mapped to port 81
    environment:
      DISABLE_IPV6: 'true'
    volumes:
      - /opt/stacks/stacks/Proxmox-Production/nginxproxymanager/database:/data
      - /opt/stacks/stacks/Proxmox-Production/nginxproxymanager/certs:/etc/letsencrypt
      #- /opt/nginxproxymanager:/data
      #- /opt/nginxproxymanager:/etc/letsencrypt

networks:
  internal_proxy:
    external: true
  openclaw_network:
    external: true

Be sure to enable websocket support.

NGINX Proxy Manager custom domain with websockets enabled. Remember to update Openclaw's config with this domain.


Openclaw HTTPS

If all goes well, you will see this page. Just paste the token (the 32 character hex) you had in your env file

Openclaw HTTPS hex token.


You will need to connect to the openclaw-cli container and approve your browser. Note that approval token.

Browser approval token


Connect to your openclaw-cli container and run this:

docker exec -it openclaw-openclaw-cli-1 node dist/index.js devices approve 8cdxxxxxxxxxxx

Then just refresh your page and then you are in!


necrolingus

Tech enthusiast and home labber