# Openclaw Helm Chart

Personal AI assistant with multi-channel support (WhatsApp, Telegram, Discord, and more) running on Kubernetes.

## TL;DR

```bash
helm install my-openclaw ./openclaw \
  --set secrets.data.anthropicApiKey=sk-ant-xxx \
  --set secrets.data.gatewayToken=$(openssl rand -hex 32)
```

## Introduction

This chart deploys Openclaw Gateway on a Kubernetes cluster using the Helm package manager.

**Important:** Openclaw is designed as a single-user personal assistant. The chart enforces `replicas: 1` and does not support horizontal scaling.

## Prerequisites

- Kubernetes 1.19+
- Helm 3.x
- PV provisioner support in the underlying infrastructure (for persistent storage)
- **Optional:** Ingress controller (NGINX, Traefik, etc.) for external access
- **Optional:** cert-manager for automatic TLS certificates

## Installing the Chart

### Basic Installation

```bash
helm install my-openclaw ./openclaw
```

### With Custom Values

```bash
helm install my-openclaw ./openclaw \
  --values examples/values-production.yaml \
  --set secrets.data.anthropicApiKey=sk-ant-xxx \
  --set ingress.hosts[0].host=assistant.example.com
```

### From Examples

```bash
# Basic (local testing)
helm install my-openclaw ./openclaw -f examples/values-basic.yaml

# Production
helm install my-openclaw ./openclaw -f examples/values-production.yaml

# Fly.io-like setup
helm install my-openclaw ./openclaw -f examples/values-fly-like.yaml
```

## Uninstalling the Chart

```bash
helm uninstall my-openclaw

# Also delete PVCs (data will be lost)
kubectl delete pvc -l app.kubernetes.io/instance=my-openclaw
```

## Configuration

### Key Parameters

| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of replicas (must be 1) | `1` |
| `image.repository` | Openclaw image repository | `openclaw/openclaw` |
| `image.tag` | Image tag | Chart appVersion |
| `gateway.bind` | Gateway binding mode (`loopback`, `lan`, `auto`) | `lan` |
| `gateway.port` | Gateway port | `18789` |
| `secrets.data.anthropicApiKey` | Anthropic API key | `""` |
| `secrets.data.openaiApiKey` | OpenAI API key | `""` |
| `secrets.data.gatewayToken` | Gateway authentication token (auto-generated if empty) | `""` |
| `persistence.enabled` | Enable persistent storage | `true` |
| `persistence.size` | PVC size | `10Gi` |
| `ingress.enabled` | Enable Ingress | `false` |
| `ingress.className` | Ingress class | `nginx` |
| `resources.limits.memory` | Memory limit | `2Gi` |
| `resources.requests.memory` | Memory request | `512Mi` |

### Full Values Reference

See [values.yaml](values.yaml) for all available parameters.

## Storage

The chart creates a StatefulSet with a persistent volume claim template that mounts storage at two locations:

- `/home/node/.openclaw` (subPath: `openclaw-state`) - Configuration, sessions, device identity, SQLite databases
- `/home/node/clawd` (subPath: `openclaw-workspace`) - Agent workspace files

**Storage Class:** By default, uses the cluster's default storage class. Override with `persistence.storageClass`.

**Size Recommendations:**
- Development/Testing: 5-10Gi
- Production (single user): 20Gi+
- Depends on session history and workspace usage

## Secrets Management

### Option 1: Inline Secrets (Development Only)

```bash
helm install my-openclaw ./openclaw \
  --set secrets.data.anthropicApiKey=sk-ant-xxx \
  --set secrets.data.gatewayToken=$(openssl rand -hex 32)
```

### Option 2: External Secret (Production)

Create a Kubernetes Secret:

```bash
kubectl create secret generic openclaw-secrets \
  --from-literal=gatewayToken=$(openssl rand -hex 32) \
  --from-literal=anthropicApiKey=sk-ant-xxx \
  --from-literal=discordBotToken=MTQ...
```

Install with existing secret:

```bash
helm install my-openclaw ./openclaw \
  --set secrets.create=false \
  --set secrets.existingSecret=openclaw-secrets
```

### Option 3: External Secrets Operator

Use External Secrets Operator to sync from Vault, AWS Secrets Manager, etc.

## Ingress

### NGINX Ingress Controller

```yaml
ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/websocket-services: "{{ include \"openclaw.fullname\" . }}"
  hosts:
    - host: assistant.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: openclaw-tls
      hosts:
        - assistant.example.com
```

**Important:** WebSocket support requires extended timeouts (3600s recommended).

### Traefik

```yaml
ingress:
  className: traefik
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
```

## Health Checks

The chart uses exec-based probes that run the CLI health command:

```yaml
livenessProbe:
  exec:
    command:
      - sh
      - -c
      - node dist/index.js health --token "${CLAWDBOT_GATEWAY_TOKEN}" || exit 1
```

## Upgrading

```bash
# Pull latest chart changes
git pull

# Upgrade with current values
helm upgrade my-openclaw ./openclaw --reuse-values

# Upgrade with new values
helm upgrade my-openclaw ./openclaw -f values-production.yaml
```

## Troubleshooting

### Pod Not Starting

```bash
# Check pod events
kubectl describe pod my-openclaw-0

# Check logs
kubectl logs my-openclaw-0
```

### OOM (Out of Memory)

Increase memory limits:

```yaml
resources:
  limits:
    memory: 4Gi
  requests:
    memory: 1Gi
```

**Note:** 512MB is too small for production. 2GB recommended minimum.

### PVC Not Binding

```bash
# Check PVC status
kubectl get pvc

# Check storage class
kubectl get storageclass

# Describe for events
kubectl describe pvc data-my-openclaw-0
```

### WebSocket Connections Timing Out

Ensure Ingress has WebSocket annotations:

```yaml
annotations:
  nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
  nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
```

### Gateway Lock File Issues

If the gateway won't start due to stale lock files:

```bash
kubectl exec my-openclaw-0 -- rm -f /home/node/.openclaw/gateway.*.lock
kubectl delete pod my-openclaw-0  # Restart pod
```

## Examples

### Local Testing (Minikube/Kind/Docker Desktop)

```bash
# Build local image
docker build -t openclaw:local .

# Load into cluster (example for Minikube)
minikube image load openclaw:local

# Install chart
helm install test ./openclaw \
  -f examples/values-basic.yaml \
  --set image.repository=openclaw \
  --set image.tag=local \
  --set image.pullPolicy=Never
```

### Production Deployment

```bash
# Create external secret first
kubectl create secret generic openclaw-secrets \
  --from-literal=gatewayToken=$(openssl rand -hex 32) \
  --from-literal=anthropicApiKey=$ANTHROPIC_API_KEY

# Install with production values
helm install my-openclaw ./openclaw -f examples/values-production.yaml
```

## Documentation

- [Openclaw Documentation](https://docs.clawd.bot)
- [Kubernetes Installation Guide](https://docs.clawd.bot/install/kubernetes)
- [GitHub Repository](https://github.com/openclaw/openclaw)

## Support

- [GitHub Issues](https://github.com/openclaw/openclaw/issues)
- [Documentation](https://docs.clawd.bot)

## License

See [LICENSE](https://github.com/openclaw/openclaw/blob/main/LICENSE)
