https://github.com/digitalocean-labs/openclaw-appplatform
Pre-built Docker image for deploying OpenClaw on DigitalOcean App Platform
https://github.com/digitalocean-labs/openclaw-appplatform
app-platform digitalocean digitalocean-app-platform openclaw
Last synced: 4 months ago
JSON representation
Pre-built Docker image for deploying OpenClaw on DigitalOcean App Platform
- Host: GitHub
- URL: https://github.com/digitalocean-labs/openclaw-appplatform
- Owner: digitalocean-labs
- License: mit
- Created: 2026-01-27T06:50:56.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-02-01T07:06:25.000Z (4 months ago)
- Last Synced: 2026-02-01T07:10:50.363Z (4 months ago)
- Topics: app-platform, digitalocean, digitalocean-app-platform, openclaw
- Language: Shell
- Homepage:
- Size: 177 KB
- Stars: 1
- Watchers: 0
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# OpenClaw on DigitalOcean App Platform
Deploy [OpenClaw](https://github.com/openclaw/openclaw) - a multi-channel AI messaging gateway - on DigitalOcean App Platform in minutes.
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/digitalocean-labs/openclaw-appplatform/tree/main)
## Quick Start: Choose Your Stage
| 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.
---
## Architecture
```
┌────────────────────────────────────────────────────────────────────┐
│ 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 │
└──────────┘ └──────────┘ └──────────┘
```
---
## Stage 1: CLI Only - The Basics
The simplest deployment. Access via `doctl apps console` and use CLI commands.
### Deploy
```bash
# 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
```
### Connect
```bash
# Get app ID
doctl apps list
# Open console
doctl apps console openclaw
# Verify gateway is running
openclaw gateway health --url ws://127.0.0.1:18789
# Check channel status
openclaw channels status --probe
```
### What's Included
- ✅ OpenClaw gateway (WebSocket on port 18789)
- ✅ CLI access via `openclaw` command
- ✅ All channel plugins (WhatsApp, Telegram, Discord, etc.)
- ❌ No web UI access (use CLI/TUI)
- ❌ No public URL
- ❌ Data lost on restart
---
## Stage 2: Add Web UI + ngrok
Add a public URL to access the Control UI. **Recommended for getting started.**
### Get ngrok Token
1. Sign up at
2. Copy your authtoken from the dashboard
### Deploy
Update `app.yaml`:
```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
```
### Get Your URL
```bash
# In console
curl -s http://127.0.0.1:4040/api/tunnels | jq -r '.tunnels[0].public_url'
```
Or check the ngrok dashboard at
### What's Added
- ✅ Everything from Stage 1
- ✅ Web Control UI
- ✅ Public URL via ngrok
- ❌ URL changes on restart (use Tailscale for stable URL)
- ❌ Data lost on restart
---
## Stage 3: Production with Tailscale
Private network access via your Tailscale tailnet. **Recommended for production.**
### Get Tailscale Auth Key
See [Setting up Tailscale](#setting-up-tailscale) for a detailed walkthrough with screenshots.
1. Go to
2. Generate a reusable auth key
### Deploy
Update `app.yaml`:
```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: openclaw
```
### Access
```
https://openclaw..ts.net
```
### What's Added
- ✅ 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)
---
## Setting up Tailscale
This section walks you through creating a Tailscale auth key for your OpenClaw deployment.
### 1. Sign in to Tailscale
Go to and sign in with your preferred identity provider (Google, Microsoft, GitHub, etc.).
### 2. Access the Admin Console
Once signed in, you'll be taken to the Tailscale admin console. This is where you manage your tailnet (your private network).
### 3. Navigate to Auth Keys
1. Click **Settings** in the left sidebar
2. Click **Keys** under the Personal Settings section
3. Or go directly to
### 4. Generate an Auth Key
1. Click **Generate auth key**
2. 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)

### 5. Copy Your Auth Key
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`
### 6. Add the Key to Your Deployment
Set the `TS_AUTHKEY` environment variable in your `app.yaml` or in the DigitalOcean dashboard:
```yaml
envs:
- key: TS_AUTHKEY
type: SECRET
value: "tskey-auth-xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx"
```
### 7. Verify the Connection
After deploying, your OpenClaw instance will appear in the **Machines** tab of your Tailscale admin console.
You can access your instance at:
```
https://..ts.net
```
---
## Adding Persistence (Any Stage)
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
### Setup DO Spaces
1. **Create a Spaces bucket** in the same region as your app
- Go to **Spaces Object Storage** → **Create Bucket**
2. **Create access keys**
- Go to **API** → **Spaces Keys** → **Generate New Key**
3. **Update app.yaml**:
```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: SECRET
```
### What Gets Persisted
The backup system uses [Restic](https://restic.net/) 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-state` init 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:///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.
---
## AI-Assisted Setup
Want an AI assistant to help deploy and configure OpenClaw? See **[AI-ASSISTED-SETUP.md](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.
---
## CLI Cheat Sheet
The `openclaw` command is a wrapper that runs openclaw with the correct user and environment. **Always use `openclaw` in console sessions.**
```bash
# 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](CHEATSHEET.md)** for the complete reference.
---
## Environment Variables
### Required
| Variable | Description |
|--------------------------|-------------------------------------|
| `OPENCLAW_GATEWAY_TOKEN` | Password for web setup wizard |
| `STABLE_HOSTNAME` | A stable hostname for this instance |
### Feature Flags
| 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 |
### ngrok (when ENABLE_NGROK=true)
| Variable | Description |
|-------------------|-----------------------|
| `NGROK_AUTHTOKEN` | Your ngrok auth token |
### Tailscale (when TAILSCALE_ENABLE=true)
| Variable | Description |
|--------------|--------------------|
| `TS_AUTHKEY` | Tailscale auth key |
### Spaces (when ENABLE_SPACES=true)
| 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 |
### Optional
| 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 |
---
## Customization (s6-overlay)
The container uses [s6-overlay](https://github.com/just-containers/s6-overlay) for process supervision.
### Dynamic MOTD
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 |
### Add Custom Init Scripts
Create `rootfs/etc/cont-init.d/30-my-script`:
```bash
#!/command/with-contenv bash
echo "Running my custom setup..."
```
### Add Custom Services
Create `rootfs/etc/services.d/my-daemon/run`:
```bash
#!/command/with-contenv bash
exec my-daemon --foreground
```
### Built-in Services
| 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) |
---
## Available Regions
| 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) |
---
## Documentation
- [OpenClaw Documentation](https://docs.openclaw.ai)
- [DigitalOcean App Platform](https://docs.digitalocean.com/products/app-platform/)
- [AI-Assisted Setup Guide](AI-ASSISTED-SETUP.md)
- [CLI Cheat Sheet](CHEATSHEET.md)
---
## License
MIT