Deploy OpenClaw - a multi-channel AI messaging gateway - on DigitalOcean App Platform in minutes.
| Stage | What You Get | Access Method |
|---|---|---|
| 1. CLI Only | Gateway + CLI | doctl apps console |
| 2. + Web UI + ngrok | Control UI + Public URL | ngrok URL |
| 3. + Tailscale | Private Network | Tailscale hostname |
| + Persistence | Data survives restarts | DO Spaces |
Start simple, add features as needed. Most users start with Stage 2 (ngrok) for the easiest setup.
┌────────────────────────────────────────────────────────────────────┐
│ openclaw-appplatform │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ s6-overlay - Process supervision and init system │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌─────────────┐ ┌───────────────────┐ │
│ │ Ubuntu │ │ OpenClaw Gateway │ │
│ │ Noble+Node │ │ WebSocket :18789 │ │
│ │ + nvm │ │ + Control UI │ │
│ └─────────────┘ └───────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Access Layer (choose one): │ │
│ │ • Console only (default) - doctl apps console │ │
│ │ • ngrok (ENABLE_NGROK) - Public tunnel to UI │ │
│ │ • Tailscale (TAILSCALE_ENABLE) - Private network │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Optional: SSH Server (SSH_ENABLE=true) │ │
│ └──────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ WhatsApp │ │ Telegram │ │ Discord │
│ Signal │ │ Slack │ │ MS Teams │
│ iMessage │ │ Matrix │ │ + more │
└──────────┘ └──────────┘ └──────────┘
The simplest deployment. Access via doctl apps console and use CLI commands.
# Clone the repo
git clone https://github.com/digitalocean-labs/openclaw-appplatform
cd openclaw-appplatform
# Edit app.yaml - set instance size for Stage 1
# instance_size_slug: apps-s-1vcpu-2gb # 1 CPU, 2GB (minimum for stable operation)
# Set your OPENCLAW_GATEWAY_TOKEN in app.yaml or DO dashboard
# Deploy
doctl apps create --spec app.yaml# Get app ID
doctl apps list
# Open console
doctl apps console <app-id> openclaw
# Verify gateway is running
openclaw gateway health --url ws://127.0.0.1:18789
# Check channel status
openclaw channels status --probe- ✅ OpenClaw gateway (WebSocket on port 18789)
- ✅ CLI access via
openclawcommand - ✅ All channel plugins (WhatsApp, Telegram, Discord, etc.)
- ❌ No web UI access (use CLI/TUI)
- ❌ No public URL
- ❌ Data lost on restart
Add a public URL to access the Control UI. Recommended for getting started.
- Sign up at https://dashboard.ngrok.com
- Copy your authtoken from the dashboard
Update app.yaml:
instance_size_slug: apps-s-1vcpu-2gb # 1 CPU, 2GB
envs:
- key: ENABLE_NGROK
value: "true"
- key: NGROK_AUTHTOKEN
type: SECRET
# Set value in DO dashboard# In console
curl -s http://127.0.0.1:4040/api/tunnels | jq -r '.tunnels[0].public_url'Or check the ngrok dashboard at https://dashboard.ngrok.com/tunnels
- ✅ Everything from Stage 1
- ✅ Web Control UI
- ✅ Public URL via ngrok
- ❌ URL changes on restart (use Tailscale for stable URL)
- ❌ Data lost on restart
Private network access via your Tailscale tailnet. Recommended for production.
See Setting up Tailscale for a detailed walkthrough with screenshots.
- Go to https://login.tailscale.com/admin/settings/keys
- Generate a reusable auth key
Update app.yaml:
instance_size_slug: apps-s-1vcpu-2gb # 1 CPU, 2GB
envs:
- key: ENABLE_NGROK
value: "false"
- key: TAILSCALE_ENABLE
value: "true"
- key: TS_AUTHKEY
type: SECRET
- key: STABLE_HOSTNAME
value: openclawhttps://openclaw.<your-tailnet>.ts.net
- ✅ Everything from Stage 1 & 2
- ✅ Stable hostname on your tailnet
- ✅ Private access (only your devices)
- ✅ Production-grade security
- ❌ Data lost on restart (add Spaces for persistence)
This section walks you through creating a Tailscale auth key for your OpenClaw deployment.
Go to https://login.tailscale.com and sign in with your preferred identity provider (Google, Microsoft, GitHub, etc.).
Once signed in, you'll be taken to the Tailscale admin console. This is where you manage your tailnet (your private network).
- Click Settings in the left sidebar
- Click Keys under the Personal Settings section
- Or go directly to https://login.tailscale.com/admin/settings/keys
- Click Generate auth key
- Configure the key settings:
- Reusable: Enable this so the key can be used if the container restarts
- Ephemeral: Optional - nodes using this key will be automatically removed when they go offline
- Tags: Optional - apply ACL tags to control access
- Expiration: Choose an appropriate expiration (default is 90 days)
After clicking Generate key, your auth key will be displayed. Copy it immediately as it won't be shown again.
The key format looks like: tskey-auth-xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx
Set the TS_AUTHKEY environment variable in your app.yaml or in the DigitalOcean dashboard:
envs:
- key: TS_AUTHKEY
type: SECRET
value: "tskey-auth-xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx"After deploying, your OpenClaw instance will appear in the Machines tab of your Tailscale admin console.
You can access your instance at:
https://<hostname>.<your-tailnet>.ts.net
Without persistence, all data is lost when the container restarts. Add DO Spaces to preserve:
- Channel sessions (WhatsApp linking, etc.)
- Configuration changes
- Memory/search index
- Tailscale state
-
Create a Spaces bucket in the same region as your app
- Go to Spaces Object Storage → Create Bucket
-
Create access keys
- Go to API → Spaces Keys → Generate New Key
-
Update app.yaml:
envs:
- key: ENABLE_SPACES
value: "true"
- key: RESTIC_SPACES_ACCESS_KEY_ID
type: SECRET
- key: RESTIC_SPACES_SECRET_ACCESS_KEY
type: SECRET
- key: RESTIC_SPACES_ENDPOINT
value: tor1.digitaloceanspaces.com # Match your region
- key: RESTIC_SPACES_BUCKET
value: openclaw-backup
- key: RESTIC_PASSWORD
type: SECRETThe backup system uses Restic for incremental, encrypted snapshots to DigitalOcean Spaces.
| Path | Contents | Backup Frequency |
|---|---|---|
/data/.openclaw |
Gateway config, channel sessions, agents, memory | Every 30s (configurable) |
/data/tailscale |
Tailscale connection state (persistent device) | Every 30s |
/etc |
System configuration | Every 30s |
/home |
User files, Homebrew packages | Every 30s |
/root |
Root user data | Every 30s |
Automatic Restore:
- On container restart,
10-restore-stateinit script automatically restores the latest snapshot for each path - Restores are fast and incremental
- Data survives deployments, restarts, and instance replacements
Repository Management:
- Old snapshots are automatically pruned every hour
- Repository is encrypted with
RESTIC_PASSWORD - Stored in:
s3:<endpoint>/<bucket>/<hostname>/restic
Configuration File:
Backup behavior is controlled by /etc/digitalocean/backup.yaml:
- Backup paths: What directories to back up
- Exclusions: Files to skip (*.lock, *.pid, *.sock)
- Intervals: Backup frequency (default: 30s), prune frequency (default: 1h)
- Retention policy: How many snapshots to keep (last 10, hourly 48, daily 30, etc.)
To customize, create rootfs/etc/digitalocean/backup.yaml in your repo and rebuild.
Want an AI assistant to help deploy and configure OpenClaw? See AI-ASSISTED-SETUP.md for:
- Copy-paste prompts for each stage
- WhatsApp channel setup (with QR code handling)
- Verification steps
- Works with Claude Code, Cursor, Codex, Gemini, etc.
The openclaw command is a wrapper that runs openclaw with the correct user and environment. Always use openclaw in console sessions.
# Gateway
openclaw gateway health --url ws://127.0.0.1:18789
openclaw gateway status
# Channels
openclaw channels status --probe
openclaw channels login # WhatsApp QR code
# Messages
openclaw message send --channel whatsapp --target "+1234567890" --message "Hello!"
# Services
/command/s6-svc -r /run/service/openclaw # Restart
/command/s6-svc -r /run/service/ngrok # Restart ngrok
# Logs
tail -f /data/.openclaw/logs/gateway.log
# Config
cat /data/.openclaw/openclaw.json | jq .See CHEATSHEET.md for the complete reference.
| Variable | Description |
|---|---|
OPENCLAW_GATEWAY_TOKEN |
Password for web setup wizard |
STABLE_HOSTNAME |
A stable hostname for this instance |
| Variable | Default | Description |
|---|---|---|
ENABLE_NGROK |
false |
Enable ngrok tunnel |
ENABLE_TAILSCALE |
false |
Enable Tailscale |
ENABLE_SPACES |
false |
Enable DO Spaces persistence |
ENABLE_UI |
true |
Enable web Control UI |
SSH_ENABLE |
false |
Enable SSH server |
| Variable | Description |
|---|---|
NGROK_AUTHTOKEN |
Your ngrok auth token |
| Variable | Description |
|---|---|
TS_AUTHKEY |
Tailscale auth key |
| Variable | Description |
|---|---|
RESTIC_SPACES_ACCESS_KEY_ID |
Spaces access key |
RESTIC_SPACES_SECRET_ACCESS_KEY |
Spaces secret key |
RESTIC_SPACES_ENDPOINT |
e.g., tor1.digitaloceanspaces.com |
RESTIC_SPACES_BUCKET |
Your bucket name |
RESTIC_PASSWORD |
Backup encryption password |
| Variable | Description |
|---|---|
OPENCLAW_GATEWAY_TOKEN |
Gateway auth token (auto-generated if not set) |
GRADIENT_API_KEY |
DigitalOcean Gradient AI key |
GITHUB_USERNAME |
For SSH key fetching |
The container uses s6-overlay for process supervision.
On login, you'll see a colorful status display. Run motd anytime to refresh.
| Section | Info |
|---|---|
| 🖥️ System | Hostname, uptime, load, memory, disk (color-coded) |
| 🔗 Tailscale | Status, IP, relay, serve URL (if enabled) |
| 🦞 OpenClaw | Health status, configured channels, agent count |
| 📚 Links | OpenClaw docs, App Platform docs, source repo |
Create rootfs/etc/cont-init.d/30-my-script:
#!/command/with-contenv bash
echo "Running my custom setup..."Create rootfs/etc/services.d/my-daemon/run:
#!/command/with-contenv bash
exec my-daemon --foreground| Service | Description |
|---|---|
openclaw |
OpenClaw gateway |
ngrok |
ngrok tunnel (if enabled) |
tailscale |
Tailscale daemon (if enabled) |
backup |
Restic backup service - creates snapshots (if enabled) |
prune |
Restic prune service - cleans old snapshots (if enabled) |
crond |
Cron daemon for scheduled tasks |
sshd |
SSH server (if enabled) |
| Code | Location |
|---|---|
nyc |
New York |
atl |
Atlanta |
ams |
Amsterdam |
sfo |
San Francisco |
sgp |
Singapore |
lon |
London |
fra |
Frankfurt |
blr |
Bangalore |
syd |
Sydney |
tor |
Toronto (default) |
MIT
