Skip to main content

Deploying OpenClaw

OpenClaw is a full-featured AI coding agent with a web UI, Telegram integration, and browser automation support. This guide walks through everything needed to deploy it on Pai correctly.

Required volumes

OpenClaw needs two persistent volumes:

volumes:
- name: openclaw-home
mountPath: /home/node/.openclaw
size: "5Gi"
- name: workspace
mountPath: /home/node/workspace
size: "10Gi"
VolumePurpose
openclaw-homeConfiguration, session state, agent memory, conversation history
workspaceWorking directory where the agent reads and writes code files

Both volumes persist across pod restarts — your config edits and workspace files survive agent updates.

Required config files

Two files must be seeded into the openclaw-home volume on first start via configFiles. OpenClaw will not start correctly without them.

openclaw.json

The main OpenClaw configuration file. It tells OpenClaw which model to use, which ACP agents to run, and which channels are enabled.

configFiles:
- path: /home/node/.openclaw/openclaw.json
content: |
{
"agents": {
"defaults": {
"model": {
"primary": "anthropic/claude-sonnet-4-6",
"fallbacks": []
}
},
"list": [
{
"id": "codex",
"runtime": {
"type": "acp",
"acp": {
"agent": "codex",
"backend": "acpx",
"mode": "persistent",
"cwd": "/home/node/workspace"
}
}
}
]
},
"acp": {
"enabled": true,
"dispatch": { "enabled": true },
"backend": "acpx",
"defaultAgent": "codex",
"maxConcurrentSessions": 4,
"runtime": {
"ttlMinutes": 120
}
},
"channels": {
"telegram": {
"enabled": true,
"dmPolicy": "pairing"
}
},
"browser": {
"enabled": true,
"attachOnly": true,
"cdpUrl": "http://localhost:8082"
}
}

Key fields explained:

FieldDescription
agents.defaults.model.primaryThe LLM model used by default. Must match an entry in auth-profiles.json
agents.listList of ACP agent runtimes. Each entry has an id that is referenced by acp.defaultAgent
agents.list[].runtime.acp.cwdWorking directory for the ACP agent — set to the workspace volume mount path
acp.defaultAgentMust match an id in agents.list
acp.maxConcurrentSessionsMaximum simultaneous chat sessions
acp.runtime.ttlMinutesHow long an idle agent session is kept alive before being recycled
channels.telegram.enabledEnable Telegram integration (requires a Telegram provider)
channels.telegram.dmPolicypairing requires users to pair via a code before chatting
browser.enabledEnable browser automation features
browser.attachOnlyOnly attach to an existing browser (via CDP relay) rather than launching a new one
browser.cdpUrlThe local CDP endpoint — keep as http://localhost:8082 when using pai relay

Model name format: OpenClaw uses provider/model-name notation — e.g. anthropic/claude-sonnet-4-6 or google/gemini-flash-2-5. This must match the provider and key fields in auth-profiles.json.

auth-profiles.json

Tells OpenClaw which LLM auth profiles are available and how to authenticate with them. On Pai, credentials are managed by the gateway — set "key": "pai-managed" and the platform injects the real API key transparently.

  - path: /home/node/.openclaw/agents/main/agent/auth-profiles.json
content: |
{
"google-gemini": {
"provider": "google",
"mode": "api-key",
"key": "pai-managed"
},
"anthropic-claude": {
"provider": "anthropic",
"mode": "api-key",
"key": "pai-managed"
}
}

Include only the profiles that correspond to model bindings attached to the agent. If you only have Gemini, omit the anthropic-claude entry (and vice versa).

important

"key": "pai-managed" is required. If you put a real API key here, it will be stored in the volume and visible inside the container — defeating Pai's credential isolation.

How configFiles seeding works

configFiles are seeded into the volume by an init container on first pod start using copy-no-clobber (cp -n). This means:

  • First start: files are written from the YAML into the volume
  • Subsequent restarts: existing files are not overwritten — your in-container edits survive

If you update configFiles in the YAML and want the change to take effect, delete the file from inside the container first:

pai exec my-agent -- rm /home/node/.openclaw/openclaw.json
# then restart the agent
pai delete agent my-agent
pai create -f my-agent.yaml

Inbound port

OpenClaw's web UI listens on port 18789. Set inbound.port to expose it:

inbound:
port: 18789
allowCIDRs:
- "YOUR.IP.ADDRESS/32" # restrict to your IP

The public URL is shown in pai list and pai status once the agent is running.

Accessing the web UI

After the agent starts, get the dashboard URL with the auth token:

pai exec my-agent -- openclaw dashboard --no-open
# Outputs: http://127.0.0.1:18789/#token=...

Replace 127.0.0.1:18789 with the agent's public URL from pai list.

Complete example

apiVersion: pai.io/v1
kind: AgentWorkload
metadata:
name: my-openclaw
spec:
image: ghcr.io/openclaw/openclaw:latest
runAsUser: 1000
modelBindings:
- claude-sonnet
providers:
- telegram-bot # optional
inbound:
port: 18789
allowCIDRs:
- "YOUR.IP.ADDRESS/32"
cdpRelay: # optional — for browser automation
token: "my-secret-token"
tokens:
maxPerDay: 50000
maxPerRequest: 8192
resources:
requests:
cpu: "1500m"
memory: "2Gi"
limits:
cpu: "2"
memory: "8Gi"
expose:
- urlPath: /downloads
directory: /home/node/.openclaw/workspace/downloads
volumes:
- name: openclaw-home
mountPath: /home/node/.openclaw
size: "5Gi"
- name: workspace
mountPath: /home/node/workspace
size: "10Gi"
configFiles:
- path: /home/node/.openclaw/openclaw.json
content: |
{
"agents": {
"defaults": {
"model": {
"primary": "anthropic/claude-sonnet-4-6",
"fallbacks": []
}
},
"list": [
{
"id": "codex",
"runtime": {
"type": "acp",
"acp": {
"agent": "codex",
"backend": "acpx",
"mode": "persistent",
"cwd": "/home/node/workspace"
}
}
}
]
},
"acp": {
"enabled": true,
"dispatch": { "enabled": true },
"backend": "acpx",
"defaultAgent": "codex",
"maxConcurrentSessions": 4,
"runtime": {
"ttlMinutes": 120
}
},
"channels": {
"telegram": {
"enabled": true,
"dmPolicy": "pairing"
}
},
"browser": {
"enabled": true,
"attachOnly": true,
"cdpUrl": "http://localhost:8082"
}
}
- path: /home/node/.openclaw/agents/main/agent/auth-profiles.json
content: |
{
"anthropic-claude": {
"provider": "anthropic",
"mode": "api-key",
"key": "pai-managed"
}
}

Optional features

FeatureWhat to add
TelegramAdd a Telegram provider and set channels.telegram.enabled: true in openclaw.json
Browser automationAdd cdpRelay.token and run pai relay my-openclaw --token <token> on your machine. See the CDP guide
File downloadsThe expose block serves /home/node/.openclaw/workspace/downloads at https://<url>/downloads