Self-hosted deployment template for OpenClaw — an open-source AI agent platform with browser automation, LLM tool use, and a Telegram channel. This repo packages a patched container image, a Helm chart, an OpenTofu module, and an ArgoCD-driven CD pipeline so you can stand up your own instance on GKE without re-deriving the wiring. Read SECURITY.md before exposing it to anything.
- Dockerfile — minimal patch on top of
ghcr.io/openclaw/openclawthat raises the gateway WebSocket payload limit from 512KB to 10MB (needed for image uploads). cloudbuild.yaml— GCP Cloud Build pipeline that builds the patched image and pushes it to Artifact Registry. Tagged<sha>-<env>, never:latest.charts/openclaw/— Helm chart for the agent: Deployment with Chromium sidecar, Service, NetworkPolicy, ExternalSecret resources, and GCS-FUSE workspace volume. Ships with no access gate (deliberate — you bring your own).charts/searxng/— Companion SearXNG sidecar chart for self-hosted web search.infra/tofu/— OpenTofu module: Artifact Registry repo, GCP service account with Workload Identity bindings, GCS workspace bucket, Secret Manager entries.infra/argocd/— ArgoCDApplicationmanifests for dev and prod environments.openclaw.json— runtime model + channels config consumed by the agent.
.
├── Dockerfile # Patches OpenClaw image: MAX_PAYLOAD_BYTES → 10MB
├── Makefile # Local config validation + helpers
├── cloudbuild.yaml # GCP Cloud Build pipeline
├── openclaw.json # OpenClaw runtime config (models, channels)
├── charts/
│ ├── openclaw/ # Helm chart for the agent + Chromium sidecar
│ └── searxng/ # Companion self-hosted web search engine
└── infra/
├── argocd/ # ArgoCD Application manifests (dev + prod)
└── tofu/ # OpenTofu: Artifact Registry, GSA, GCS bucket, secrets
- Kubernetes: GKE (any cluster with NetworkPolicy enforcement works; the chart is portable)
- Identity: GCP Workload Identity binding the in-cluster ServiceAccount to a GSA
- Container registry: GCP Artifact Registry
- Secrets: External Secrets Operator projecting GCP Secret Manager into Kubernetes Secrets
- Workspace volume: GCS-FUSE CSI driver, mounting a GCS bucket at
/home/node/.openclaw - CI: GCP Cloud Build (one job: build patched image, push to Artifact Registry)
- CD: ArgoCD, optionally with
argocd-image-updaterto auto-bump tags - Templating: Helm 3
The chart is the portable artifact. Every other component above has a substitute on non-GCP / non-ArgoCD setups — see Customizing.
- A GCP project with billing enabled and the relevant APIs on (
artifactregistry,secretmanager,cloudbuild,container,storage). - A GKE cluster with Workload Identity and the GCS-FUSE CSI driver enabled.
- ArgoCD installed in the cluster.
- External Secrets Operator installed and a
ClusterSecretStorenamedgcp-secret-managerconfigured against your GCP project. - An LLM API key — at minimum a Google AI Studio (Gemini) key. An Anthropic key only if you intend to use the
opusorsonnetaliases. - An access gate of your choice (IAP, Cloudflare Access, oauth2-proxy, Tailscale Funnel — see SECURITY.md). The chart does not ship one.
This template wires up an LLM agent with browser automation, persistent filesystem, internet egress, and a Telegram channel. Defaults are tuned for getting started, not for safety. Specifically: the Telegram channel ships with dmPolicy: open (anyone who finds the bot can run agent tasks on your dime), the chart has no built-in access gate, the agent's web tool is a vector for prompt-injection-to-tool-execution, and there is no built-in spend cap on the LLM APIs. Read SECURITY.md before deploying.
The full path: provision infrastructure with Tofu, populate secrets, build the first image, then apply the ArgoCD app.
cd infra/tofu
tofu init
tofu plan -var project_id=<PROJECT_ID> -var region=<REGION>
tofu apply -var project_id=<PROJECT_ID> -var region=<REGION>This creates:
- An Artifact Registry repo named
openclawin<REGION>. - A GSA
openclaw-app@<PROJECT_ID>.iam.gserviceaccount.comwith Workload Identity bindings to the in-clusteropenclawServiceAccount. - A GCS workspace bucket (defaults to
<PROJECT_ID>-openclaw-workspace; override with-var workspace_bucket_name=<name>). - Empty Secret Manager entries:
openclaw-dev-anthropic-api-key,openclaw-dev-telegram-bot-token,openclaw-dev-gateway-token,google-gemini-api-key.
Capture the outputs — you'll need service_account_email and workspace_bucket for the Helm values.
The Tofu module creates the secret containers but does not write values. Add a version to each:
echo -n "<your-gemini-api-key>" | gcloud secrets versions add google-gemini-api-key --data-file=-
echo -n "<your-anthropic-api-key>"| gcloud secrets versions add openclaw-dev-anthropic-api-key --data-file=-
echo -n "<your-telegram-bot-token>"| gcloud secrets versions add openclaw-dev-telegram-bot-token --data-file=-
openssl rand -hex 32 | tr -d '\n' | gcloud secrets versions add openclaw-dev-gateway-token --data-file=-If you're not running Telegram, skip the bot token and disable the Telegram channel in openclaw.json (see SECURITY.md §2.2).
gcloud builds submit \
--config=cloudbuild.yaml \
--substitutions=_ENV=dev,_GCS_BUCKET=<workspace-bucket-name>,SHORT_SHA=$(git rev-parse --short HEAD)_GCS_BUCKET defaults to MUST_BE_SET — the build fails fast if you forget to override it. The first build also seeds openclaw.json into the workspace bucket if no copy is present.
Edit charts/openclaw/values.yaml and replace these placeholders:
openclaw.image.repository—<REGION>-docker.pkg.dev/<PROJECT_ID>/openclaw/openclawserviceAccount.annotations.iam.gke.io/gcp-service-account—openclaw-app@<PROJECT_ID>.iam.gserviceaccount.comgcs.bucket— your workspace bucket nameopenclaw.env.GOOGLE_CLOUD_PROJECTandGOOGLE_CLOUD_LOCATION— your project + region (vestigial unless you switch to Vertex AI; see Models & API keys)
Edit infra/argocd/application-dev.yaml and replace <your-org>, <PROJECT_ID>, and <REGION> placeholders. Then:
kubectl apply -f infra/argocd/application-dev.yamlArgoCD will sync the chart into namespace openclaw-dev. Check pod readiness:
kubectl -n openclaw-dev get pods -wOnce running, do not expose the Service publicly without an access gate. See SECURITY.md §2.1 for options.
OpenClaw is an LLM-driven agent: every step in a task is an LLM call. Cost and reliability are dominated by which models you wire up. The defaults below are tuned for cheap-by-default, escalate-on-need.
Defined in openclaw.json under agents.defaults.models. The primary is used unless it errors out, in which case the agent walks the fallbacks list in order.
| Alias | Model ID | Role | Notes |
|---|---|---|---|
flash |
google/gemini-2.5-flash |
Primary | Default. Cheapest of the configured Gemini tier. temperature: 0.4. |
pro |
google/gemini-2.5-pro |
Fallback | Higher reasoning, much more expensive per token. temperature: 0.2. |
lite |
google/gemini-2.5-flash-lite |
Fallback | Fastest and cheapest; weakest reasoning. |
opus |
anthropic/claude-opus-4-5 |
Optional | Highest quality, highest cost. Off by default. |
sonnet |
anthropic/claude-sonnet-4 |
Optional | Balanced Anthropic option. Off by default. |
To swap the primary, edit agents.defaults.model.primary in openclaw.json and redeploy. Aliases can be referenced from agent prompts (@opus, @sonnet) for per-task overrides.
The Helm chart expects these Kubernetes Secrets (names defined in charts/openclaw/values.yaml under externalSecrets):
openclaw-gemini-credentials— Google AI Studio / Gemini API key. Required for the default model. Get one at aistudio.google.com/app/apikey.openclaw-anthropic-credentials— Anthropic API key. Only required if you actually invokeopusorsonnetaliases. Get one at console.anthropic.com.- (No other LLM credentials are needed unless you switch to Vertex AI — see below.)
The default chart projects these via External Secrets Operator pointing at GCP Secret Manager. If you don't run ESO, you can replace the ExternalSecret resources with plain Secret manifests, or use any equivalent (Sealed Secrets, sops-nix, Vault Agent Injector, raw kubectl create secret). The pod only cares that the named Secret exists with the right key; how it gets there is your choice.
Pricing as of early 2026 — always re-verify on the provider pages before signing up (Google AI pricing, Anthropic pricing):
| Model | Input ($/1M tok) | Output ($/1M tok) | Relative cost |
|---|---|---|---|
| Gemini 2.5 Flash-Lite | ~$0.10 | ~$0.40 | 0.5x |
| Gemini 2.5 Flash | ~$0.30 | ~$2.50 | 1x (baseline) |
| Gemini 2.5 Pro | ~$1.25 | ~$10 | ~10-15x |
| Claude Sonnet 4 | ~$3 | ~$15 | ~10-15x |
| Claude Opus 4.5 | ~$15 | ~$75 | ~50-60x |
Real-world order of magnitude per agent task (10-20 LLM turns including DOM dumps from the Chromium sidecar, which are token-heavy):
- On
flash: typically $0.01-$0.05 per task. - On
proorsonnet: typically $0.10-$0.40 per task. - On
opus: typically $0.50-$2.00 per task, occasionally more on long browser sessions.
These vary wildly with page size, number of tool calls, and how much retry/replanning happens. Treat them as ballpark, not contract.
OpenClaw originally talked to Gemini through Vertex AI, then switched to the Gemini API for simpler self-hosting. The chart still carries GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION env vars in values.yaml — these are vestigial for the default Gemini API path and only matter if you switch back.
| Gemini API (default) | Vertex AI | |
|---|---|---|
| Auth | Static API key | GCP Workload Identity → service account |
| Billing | Google AI Studio account | Your GCP project |
| Required env | GOOGLE_GEMINI_API_KEY |
GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION |
| Required IAM | None | roles/aiplatform.user on the GSA |
| Data residency / VPC-SC | No | Yes |
| Easy to run off-GCP | Yes | Painful |
Recommendation: stick with the Gemini API for most self-hosted deployments. Use Vertex if you're already on GCP and need region pinning, VPC Service Controls, or unified GCP billing.
Spend caps are not optional on an LLM-driven agent. Set them before you ever run an unattended task.
- Anthropic: set a monthly spend limit in the Anthropic console (Settings → Limits). Hard cap, not soft.
- Gemini API: create a Google Cloud Budget alert on the Google AI Studio billing account, and wire the Pub/Sub notification to a Cloud Function that disables or rotates the API key when the cap trips. Budget alerts alone do not stop spend.
- Vertex AI: standard GCP budget + billing-account-disable-on-threshold pattern.
- Provider rate limits: configure RPM caps in the Anthropic and Google consoles. This is your last line of defense against a runaway agent loop hammering the API at machine speed.
- Trim unused aliases. If you're never going to call Opus, delete it from
openclaw.json. Smaller surface area = smaller blast radius if the agent picks an unexpected fallback. - Pick the cheapest model that gets the job done. Don't reach for Opus by default.
Agent tasks are not single LLM calls. A typical browser-automation task fans out to dozens of model invocations: planner → DOM observation → tool selection → result reflection → next step, repeated until done. Running every step on a frontier model burns budget without proportionate quality gain — most steps are mechanical (read DOM, pick the next button, decide if a form is filled).
The cost-sane pattern is the model router: cheap-fast model for the inner loop, escalation to a stronger model only when the cheap one fails or low-confidence-signals fire. OpenClaw's primary + fallbacks config implements the simple version of this. Flash handles ~80% of agent steps acceptably; Pro/Sonnet/Opus exist for the steps where reasoning depth actually matters.
If you find yourself wanting Opus everywhere, that's usually a signal the agent prompt or tool design needs work, not that the model is too weak.
The Helm chart is the portable artifact — everything else is swappable.
-
GCS-FUSE workspace volume → swap
gcs.enabled: truefor any RWX volume your cluster supports (NFS, EFS, Azure Files, Longhorn, aPersistentVolumeClaimwithReadWriteMany). The agent only requires that/home/node/.openclawis writable and persistent. -
External Secrets Operator → replace the
ExternalSecretresources with plainSecretmanifests, Sealed Secrets, sops-nix, Vault Agent Injector, orkubectl create secret. The pod only references Secrets by name. -
Cloud Build CI → run
docker buildin any CI (GitHub Actions, GitLab CI, BuildKite, Jenkins) and push to any OCI registry (ECR, GHCR, Docker Hub, Quay). Updateimage.repositoryaccordingly. -
ArgoCD → run
helm installorhelm upgradedirectly:helm install openclaw ./charts/openclaw \ --namespace openclaw-dev --create-namespace \ -f charts/openclaw/values.yaml
-
Artifact Registry → use any registry that the cluster can pull from with appropriate
imagePullSecrets.
The Tofu module is GCP-specific by design. On other clouds, recreate its outputs (a registry, a workspace volume, a way to project secrets into the cluster) using whatever's idiomatic for your stack.
See LICENSE.