Skip to content

Commit 45e6594

Browse files
paulgnzclaude
andcommitted
docs: add multi-tenant deployment guide to infrastructure docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1963703 commit 45e6594

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

docs/infrastructure.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,134 @@ curl https://agent.yourdomain.com/.well-known/agent.json
426426

427427
---
428428

429+
## Managed Agent Deployment (deploy.xpragents.com)
430+
431+
The deploy service provides 1-click agent provisioning via a web wizard at [deploy.xpragents.com](https://deploy.xpragents.com). It creates an XPR account, registers the agent on-chain, and deploys a Cloudflare Worker running OpenClaw with all XPR agent skills.
432+
433+
### Two Deployment Modes
434+
435+
| Mode | How It Works | Deploy Time | When Used |
436+
|------|-------------|-------------|-----------|
437+
| **Single-tenant** | One CF Worker per agent (`xpr-{owner}-{agent}.workers.dev`) | ~5 min | Default when KV not configured |
438+
| **Multi-tenant** | Shared CF Worker + per-agent KV config | ~2 sec | When `CF_KV_NAMESPACE_ID` + `CF_GATEWAY_WORKER_NAME` env vars set |
439+
440+
### Multi-Tenant Architecture
441+
442+
In multi-tenant mode, all agents share a single Cloudflare Worker deployment (the "gateway"). Each agent gets its own:
443+
- **KV config entry** with API keys, XPR account, tokens
444+
- **Sandbox container** (Cloudflare Durable Object + container instance)
445+
- **R2 storage prefix** for persistent data
446+
447+
```
448+
Request: https://alice.xpragents.com/chat
449+
|
450+
v
451+
Gateway Worker: extract subdomain "alice"
452+
|
453+
v
454+
KV lookup: AGENT_KV.get("agent:alice") -> {xprAccount, anthropicApiKey, ...}
455+
|
456+
v
457+
Sandbox: getSandbox(env.Sandbox, "alice") -> separate container per agent
458+
|
459+
v
460+
Merge env: global Worker secrets + tenant KV config -> container env vars
461+
|
462+
v
463+
Proxy: HTTP/WebSocket to OpenClaw gateway on port 18789
464+
```
465+
466+
### Key Components
467+
468+
| Component | Location | Description |
469+
|-----------|----------|-------------|
470+
| Deploy Frontend | `deploy/frontend/` (Vercel) | React wizard for agent provisioning |
471+
| Deploy Backend | `xpr-deploy-service` (Railway) | Express API for account creation + CF deployment |
472+
| Gateway Worker | `moltworker-xpr` (CF Workers) | Shared Cloudflare Worker running OpenClaw containers |
473+
| Agent Registry | `agentcore` (on-chain) | Smart contract storing agent metadata + endpoints |
474+
475+
### Gateway Startup Flow
476+
477+
When a request hits a multi-tenant agent:
478+
479+
1. **Tenant resolution** — Extract subdomain from hostname, look up KV config
480+
2. **Env merge** — Overlay tenant-specific config onto global Worker env
481+
3. **Gateway prewarm**`waitUntil(ensureMoltbotGateway())` starts the container BEFORE auth (critical — otherwise auth middleware blocks container startup)
482+
4. **Wallet auth** — User signs with XPR wallet, JWT cookie issued
483+
5. **Proxy** — HTTP/WebSocket proxied to OpenClaw gateway inside container
484+
485+
### Required Environment Variables
486+
487+
#### Deploy Service (Railway)
488+
489+
```bash
490+
# Core
491+
XPR_RPC_ENDPOINT=https://rpc.api.mainnet.metalx.com
492+
XPR_NETWORK=mainnet
493+
API_SECRET=<openssl rand -hex 32>
494+
WEBHOOK_SECRET=<openssl rand -hex 32>
495+
KEY_ENCRYPTION_SECRET=<openssl rand -hex 32> # AES-256, exactly 64 hex chars
496+
DEPLOY_ACCOUNT=agentcreate
497+
DEPLOY_PRIVATE_KEY=PVT_K1_...
498+
CF_ACCOUNT_ID=<cloudflare-account-id>
499+
CF_API_TOKEN=<cloudflare-api-token>
500+
JWT_SECRET=<openssl rand -hex 32>
501+
502+
# Multi-tenant mode (enables shared gateway)
503+
CF_KV_NAMESPACE_ID=900a672e08c1402ebb1b2e8e7889dbef
504+
CF_GATEWAY_WORKER_NAME=xpr-agent-sandbox
505+
```
506+
507+
#### Gateway Worker (CF Secrets)
508+
509+
```bash
510+
# Always required
511+
ANTHROPIC_API_KEY=<key>
512+
MOLTBOT_GATEWAY_TOKEN=<openssl rand -hex 32>
513+
514+
# Single-tenant (set per worker)
515+
XPR_ACCOUNT=<agent-account>
516+
XPR_PRIVATE_KEY=PVT_K1_...
517+
XPR_OWNER_ACCOUNT=<owner-account>
518+
519+
# Multi-tenant agents get these from KV instead of Worker secrets
520+
```
521+
522+
### Container Configuration
523+
524+
The OpenClaw container requires `OPENCLAW_GATEWAY_TOKEN` to start (since v2026.1.29). The gateway Worker:
525+
1. Passes the token as a container env var
526+
2. Injects the token server-side into WebSocket URLs via `wsConnect()`
527+
3. Users never see the token — it's handled transparently
528+
529+
Cold start takes ~90 seconds. The loading page polls `/api/status` every 5 seconds with a 5-minute max timeout.
530+
531+
### R2 Storage Isolation
532+
533+
Multi-tenant agents use prefix-based isolation in a shared R2 bucket:
534+
- Single-tenant: `r2:moltbot-data/openclaw/`
535+
- Multi-tenant: `r2:moltbot-data/{agentName}/openclaw/`
536+
537+
### Operational Commands
538+
539+
```bash
540+
# Check KV config for an agent
541+
npx wrangler kv key get --remote --namespace-id 900a672e08c1402ebb1b2e8e7889dbef "agent:myagent"
542+
543+
# List all tenant configs
544+
npx wrangler kv key list --remote --namespace-id 900a672e08c1402ebb1b2e8e7889dbef
545+
546+
# View live gateway logs
547+
cd /tmp/moltworker-xpr && npx wrangler tail
548+
549+
# Build and deploy gateway
550+
cd /tmp/moltworker-xpr && npm run build && npx wrangler deploy
551+
```
552+
553+
> **Important:** Always run `npm run build` before `npx wrangler deploy` — Wrangler uses pre-built `dist/` and does NOT rebuild automatically.
554+
555+
---
556+
429557
## Architecture Details
430558

431559
See [CLAUDE.md](../CLAUDE.md) for:

0 commit comments

Comments
 (0)