Caricamento in corso...
Caricamento in corso...
Last synced: Today, 22:00
Technical reference for the OpenClaw framework. Real-time synchronization with the official documentation engine.
Use this file to discover all available pages before exploring further.
Goal: OpenClaw Gateway running on a Fly.io machine with persistent storage, automatic HTTPS, and Discord/channel access.
fly.tomlfly deploytext# Create a new Fly app (pick your own name) fly apps create my-openclaw # Create a persistent volume (1GB is usually enough) fly volumes create openclaw_data --size 1 --region iad ``` **Tip:** Choose a region close to you. Common options: `lhr` (London), `iad` (Virginia), `sjc` (San Jose).
text**Security note:** The default config exposes a public URL. For a hardened deployment with no public IP, see [Private Deployment](#private-deployment-hardened) or use `fly.private.toml`. ```toml} app = "my-openclaw" # Your app name primary_region = "iad" [build] dockerfile = "Dockerfile" [env] NODE_ENV = "production" OPENCLAW_PREFER_PNPM = "1" OPENCLAW_STATE_DIR = "/data" NODE_OPTIONS = "--max-old-space-size=1536" [processes] app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan" [http_service] internal_port = 3000 force_https = true auto_stop_machines = false auto_start_machines = true min_machines_running = 1 processes = ["app"] [[vm]] size = "shared-cpu-2x" memory = "2048mb" [mounts] source = "openclaw_data" destination = "/data" ``` **Key settings:** | Setting | Why | | ------------------------------ | --------------------------------------------------------------------------- | | `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway | | `--allow-unconfigured` | Starts without a config file (you'll create one after) | | `internal_port = 3000` | Must match `--port 3000` (or `OPENCLAW_GATEWAY_PORT`) for Fly health checks | | `memory = "2048mb"` | 512MB is too small; 2GB recommended | | `OPENCLAW_STATE_DIR = "/data"` | Persists state on the volume |
text# Model provider API keys fly secrets set ANTHROPIC_API_KEY=sk-ant-... # Optional: Other providers fly secrets set OPENAI_API_KEY=sk-... fly secrets set GOOGLE_API_KEY=... # Channel tokens fly secrets set DISCORD_BOT_TOKEN=MTQ... ``` **Notes:** * Non-loopback binds (`--bind lan`) require a valid gateway auth path. This Fly.io example uses `OPENCLAW_GATEWAY_TOKEN`, but `gateway.auth.password` or a correctly configured non-loopback `trusted-proxy` deployment also satisfy the requirement. * Treat these tokens like passwords. * **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `openclaw.json` where they could be accidentally exposed or logged.
textFirst deploy builds the Docker image (\~2-3 minutes). Subsequent deploys are faster. After deployment, verify: ```bash} fly status fly logs ``` You should see: ``` [gateway] listening on ws://0.0.0.0:3000 (PID xxx) [discord] logged in to discord as xxx ```
text```bash} fly ssh console ``` Create the config directory and file: ```bash} mkdir -p /data cat > /data/openclaw.json << 'EOF' { "agents": { "defaults": { "model": { "primary": "anthropic/claude-opus-4-6", "fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"] }, "maxConcurrent": 4 }, "list": [ { "id": "main", "default": true } ] }, "auth": { "profiles": { "anthropic:default": { "mode": "token", "provider": "anthropic" }, "openai:default": { "mode": "token", "provider": "openai" } } }, "bindings": [ { "agentId": "main", "match": { "channel": "discord" } } ], "channels": { "discord": { "enabled": true, "groupPolicy": "allowlist", "guilds": { "YOUR_GUILD_ID": { "channels": { "general": { "allow": true } }, "requireMention": false } } } }, "gateway": { "mode": "local", "bind": "auto", "controlUi": { "allowedOrigins": [ "https://my-openclaw.fly.dev", "http://localhost:3000", "http://127.0.0.1:3000" ] } }, "meta": {} } EOF ``` **Note:** With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`. **Note:** Replace `https://my-openclaw.fly.dev` with your real Fly app origin. Gateway startup seeds local Control UI origins from the runtime `--bind` and `--port` values so first boot can proceed before config exists, but browser access through Fly still needs the exact HTTPS origin listed in `gateway.controlUi.allowedOrigins`. **Note:** The Discord token can come from either: * Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets) * Config file: `channels.discord.token` If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically. Restart to apply: ```bash} exit fly machine restart <machine-id> ```
textOpen in browser: ```bash} fly open ``` Or visit `https://my-openclaw.fly.dev/` Authenticate with the configured shared secret. This guide uses the gateway token from `OPENCLAW_GATEWAY_TOKEN`; if you switched to password auth, use that password instead. ### Logs ```bash} fly logs # Live logs fly logs --no-tail # Recent logs ``` ### SSH Console ```bash} fly ssh console ```
The gateway is binding to
127.0.0.10.0.0.0Fix: Add
--bind lanfly.tomlFly can't reach the gateway on the configured port.
Fix: Ensure
internal_port--port 3000OPENCLAW_GATEWAY_PORT=3000Container keeps restarting or getting killed. Signs:
SIGABRTv8::internal::Runtime_AllocateInYoungGenerationFix: Increase memory in
fly.tomltoml[[vm]] memory = "2048mb"
Or update an existing machine:
bashfly machine update <machine-id> --vm-memory 2048 -y
Note: 512MB is too small. 1GB may work but can OOM under load or with verbose logging. 2GB is recommended.
Gateway refuses to start with "already running" errors.
This happens when the container restarts but the PID lock file persists on the volume.
Fix: Delete the lock file:
bashfly ssh console --command "rm -f /data/gateway.*.lock" fly machine restart <machine-id>
The lock file is at
/data/gateway.*.lock--allow-unconfigured/data/openclaw.jsongateway.mode="local"Verify the config exists:
bashfly ssh console --command "cat /data/openclaw.json"
The
fly ssh console -Cbash# Use echo + tee (pipe from local to remote) echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json" # Or use sftp fly sftp shell > put /local/path/config.json /data/openclaw.json
Note:
fly sftpbashfly ssh console --command "rm /data/openclaw.json"
If you lose auth profiles, channel/provider state, or sessions after a restart, the state dir is writing to the container filesystem.
Fix: Ensure
OPENCLAW_STATE_DIR=/datafly.tomlbash# Pull latest changes git pull # Redeploy fly deploy # Check health fly status fly logs
If you need to change the startup command without a full redeploy:
bash# Get machine ID fly machines list # Update command fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y # Or with memory increase fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
Note: After
fly deployfly.tomlBy default, Fly allocates public IPs, making your gateway accessible at
https://your-app.fly.devFor a hardened deployment with no public exposure, use the private template.
Use
fly.private.tomlbash# Deploy with private config fly deploy -c fly.private.toml
Or convert an existing deployment:
bash# List current IPs fly ips list -a my-openclaw # Release public IPs fly ips release <public-ipv4> -a my-openclaw fly ips release <public-ipv6> -a my-openclaw # Switch to private config so future deploys don't re-allocate public IPs # (remove [http_service] or deploy with the private template) fly deploy -c fly.private.toml # Allocate private-only IPv6 fly ips allocate-v6 --private -a my-openclaw
After this,
fly ips listprivatetextVERSION IP TYPE REGION v6 fdaa:x:x:x:x::x private global
Since there's no public URL, use one of these methods:
Option 1: Local proxy (simplest)
bash# Forward local port 3000 to the app fly proxy 3000:3000 -a my-openclaw # Then open http://localhost:3000 in browser
Option 2: WireGuard VPN
bash# Create WireGuard config (one-time) fly wireguard create # Import to WireGuard client, then access via internal IPv6 # Example: http://[fdaa:x:x:x:x::x]:3000
Option 3: SSH only
bashfly ssh console -a my-openclaw
If you need webhook callbacks (Twilio, Telnyx, etc.) without public exposure:
Example voice-call config with ngrok:
json5{ plugins: { entries: { "voice-call": { enabled: true, config: { provider: "twilio", tunnel: { provider: "ngrok" }, webhookSecurity: { allowedHosts: ["example.ngrok.app"], }, }, }, }, }, }
The ngrok tunnel runs inside the container and provides a public webhook URL without exposing the Fly app itself. Set
webhookSecurity.allowedHosts| Aspect | Public | Private |
|---|---|---|
| Internet scanners | Discoverable | Hidden |
| Direct attacks | Possible | Blocked |
| Control UI access | Browser | Proxy/VPN |
| Webhook delivery | Direct | Via tunnel |
fly ssh console/dataWith the recommended config (
shared-cpu-2xSee Fly.io pricing for details.
© 2024 TaskFlow Mirror
Powered by TaskFlow Sync Engine