OpenClaw Deployment Guide
OpenClaw Deployment Guide
Section titled “OpenClaw Deployment Guide”Status: Live as of 2026-02-27 URL: https://claw.baseworks.com Server:
baseworks-claw(46.224.129.16)
Architecture
Section titled “Architecture”Browser | vCloudflare (edge SSL, DDoS protection) | vnginx (origin cert + HTTP Basic Auth) | vOpenClaw Gateway (port 18789, localhost only) | vOpenRouter API (LLM provider)OpenClaw is the “brain” layer (natural language, agent routing, memory). n8n (on the separate Agents VPS) is the “hands” layer (deterministic execution, file writes, API calls, Slack posts). OpenClaw calls n8n via webhooks.
Server Details
Section titled “Server Details”| Field | Value |
|---|---|
| Provider | Hetzner via xCloud |
| Server name | baseworks-claw |
| IP | 46.224.129.16 |
| OS | Ubuntu 24.04.4 LTS |
| Specs | CX33 — 4 vCPU, 8GB RAM, 75GB disk |
| Docker | 29.2.1 |
| SSH | ssh patrick@46.224.129.16 |
Access Credentials
Section titled “Access Credentials”ssh patrick@46.224.129.16Patrick has passwordless sudo via /etc/sudoers.d/patrick.
HTTP Basic Auth (nginx layer)
Section titled “HTTP Basic Auth (nginx layer)”- Username:
agents@baseworks.com - Password:
ouqUAZuwVwhWYuS8riZLsUFj
OpenClaw Gateway Token
Section titled “OpenClaw Gateway Token”de0b1a3a7023da19d797bbcc11c830880029828df65907c00494427a72d211aaDashboard URL (auto-authenticates)
Section titled “Dashboard URL (auto-authenticates)”https://claw.baseworks.com/#token=de0b1a3a7023da19d797bbcc11c830880029828df65907c00494427a72d211aaOpenRouter API Key
Section titled “OpenRouter API Key”Same key as n8n VPS. Stored in:
/opt/baseworks-claw/openclaw/.env/opt/baseworks-claw/config/openclaw.json
File Locations
Section titled “File Locations”| Path | Purpose |
|---|---|
/opt/baseworks-claw/openclaw/ | Git repo (cloned from github.com/openclaw/openclaw) |
/opt/baseworks-claw/openclaw/.env | Docker Compose environment variables |
/opt/baseworks-claw/openclaw/docker-compose.yml | Main compose file (from repo) |
/opt/baseworks-claw/openclaw/docker-compose.override.yml | Our override (adds OPENROUTER_API_KEY) |
/opt/baseworks-claw/config/ | OpenClaw config (mounted into container) |
/opt/baseworks-claw/config/openclaw.json | Main config file |
/opt/baseworks-claw/workspace/ | OpenClaw workspace (files available to agents) |
/opt/baseworks-claw/state/ | Persistent state |
/opt/baseworks-claw/credentials/ | Credentials storage |
/etc/nginx/sites-available/claw.baseworks.com | nginx site config |
/etc/nginx/.openclaw_htpasswd | HTTP Basic Auth credentials |
/etc/ssl/cloudflare/baseworks.com.pem | Cloudflare origin certificate |
/etc/ssl/cloudflare/baseworks.com.key | Cloudflare origin private key |
Configuration
Section titled “Configuration”openclaw.json
Section titled “openclaw.json”{ "gateway": { "mode": "local", "bind": "lan", "port": 18789, "auth": { "mode": "token", "token": "<gateway-token>" }, "controlUi": { "allowedOrigins": ["https://claw.baseworks.com"] } }, "models": { "providers": { "openrouter": { "baseUrl": "https://openrouter.ai/api/v1", "apiKey": "<openrouter-key>", "models": [ { "id": "anthropic/claude-sonnet-4", "name": "Claude Sonnet 4 (OpenRouter)", "input": ["text", "image"], "contextWindow": 200000, "maxTokens": 16384 }, { "id": "anthropic/claude-haiku-4", "name": "Claude Haiku 4 (OpenRouter)", "input": ["text", "image"], "contextWindow": 200000, "maxTokens": 16384 }, { "id": "google/gemini-2.0-flash-001", "name": "Gemini 2.0 Flash (OpenRouter)", "input": ["text", "image"], "contextWindow": 1000000, "maxTokens": 8192 } ] } } }}nginx config
Section titled “nginx config”server { listen 80; server_name claw.baseworks.com; return 301 https://$host$request_uri;}
server { listen 443 ssl; server_name claw.baseworks.com;
ssl_certificate /etc/ssl/cloudflare/baseworks.com.pem; ssl_certificate_key /etc/ssl/cloudflare/baseworks.com.key;
location / { auth_basic "OpenClaw — Baseworks"; auth_basic_user_file /etc/nginx/.openclaw_htpasswd;
proxy_pass http://127.0.0.1:18789; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s; proxy_send_timeout 86400s; }}docker-compose.override.yml
Section titled “docker-compose.override.yml”services: openclaw-gateway: environment: OPENROUTER_API_KEY: ${OPENROUTER_API_KEY} openclaw-cli: environment: OPENROUTER_API_KEY: ${OPENROUTER_API_KEY}Common Operations
Section titled “Common Operations”View live logs
Section titled “View live logs”cd /opt/baseworks-claw/openclawsudo docker compose logs -f openclaw-gatewayHealth check
Section titled “Health check”sudo docker exec openclaw-openclaw-gateway-1 node dist/index.js healthRestart gateway
Section titled “Restart gateway”cd /opt/baseworks-claw/openclawsudo docker compose down && sudo docker compose up -d openclaw-gatewayApprove a new device
Section titled “Approve a new device”cd /opt/baseworks-claw/openclawsudo docker compose exec openclaw-gateway node dist/index.js devices listsudo docker compose exec openclaw-gateway node dist/index.js devices approve <requestId>Run doctor
Section titled “Run doctor”cd /opt/baseworks-claw/openclawsudo docker compose run --rm openclaw-cli doctor --fixUpdate OpenClaw
Section titled “Update OpenClaw”cd /opt/baseworks-claw/openclawsudo git pullsudo docker build -t openclaw:local -f Dockerfile .sudo docker compose down && sudo docker compose up -d openclaw-gatewayAdd messaging channels
Section titled “Add messaging channels”# WhatsApp (QR code):sudo docker compose run --rm openclaw-cli channels login
# Telegram:sudo docker compose run --rm openclaw-cli channels add --channel telegram --token <bot-token>
# Slack:sudo docker compose run --rm openclaw-cli channels add --channel slack --token <bot-token>Adding a New User / Colleague
Section titled “Adding a New User / Colleague”There are 3 layers to grant access through. All 3 are required.
Step 1: Create nginx Basic Auth credentials
Section titled “Step 1: Create nginx Basic Auth credentials”SSH into the server and add a new username/password:
ssh patrick@46.224.129.16sudo htpasswd /etc/nginx/.openclaw_htpasswd 'colleague@baseworks.com'# You'll be prompted to set a password — share it with your colleague securelyTo list existing users:
sudo cat /etc/nginx/.openclaw_htpasswdTo remove a user:
sudo htpasswd -D /etc/nginx/.openclaw_htpasswd 'colleague@baseworks.com'Step 2: Share the dashboard URL with token
Section titled “Step 2: Share the dashboard URL with token”Send your colleague this URL (it includes the gateway token so the UI auto-authenticates):
https://claw.baseworks.com/#token=de0b1a3a7023da19d797bbcc11c830880029828df65907c00494427a72d211aaAlong with their nginx Basic Auth username and password from Step 1.
Step 3: Approve their device pairing
Section titled “Step 3: Approve their device pairing”When your colleague opens the URL for the first time, they’ll see “pairing required”. Their browser needs to be approved from the server:
ssh patrick@46.224.129.16cd /opt/baseworks-claw/openclaw
# List pending pairing requests — find their requestIdsudo docker compose exec openclaw-gateway node dist/index.js devices list
# Approve their devicesudo docker compose exec openclaw-gateway node dist/index.js devices approve <requestId>After approval, they should click Connect in the dashboard and it will go green.
Summary: what to send your colleague
Section titled “Summary: what to send your colleague”
- Go to:
https://claw.baseworks.com/#token=de0b1a3a7023da19d797bbcc11c830880029828df65907c00494427a72d211aa- When the browser prompts for a username/password, enter:
colleague@baseworks.com/<password>- You’ll see “pairing required” — let Patrick know and he’ll approve your device from the server
- Once approved, click Connect
How the authentication flow works
Section titled “How the authentication flow works”There are 3 layers a user must pass through, in order:
Browser opens URL │ ▼Layer 1: nginx Basic Auth (username + password prompt) │ ✓ Credentials match /etc/nginx/.openclaw_htpasswd ▼Layer 2: Gateway Token (stored in browser local storage) │ ✓ Token matches the one in openclaw.json ▼Layer 3: Device Pairing (one-time per browser) │ ✗ "pairing required" — new device not yet trusted │ → Server admin runs: devices approve <requestId> │ ✓ Device is now permanently paired ▼Connected — full access to Control UIDay-to-day login: Only Layer 1 (username + password) is needed. The gateway token persists in browser local storage, and device pairing is permanent. You won’t be prompted for the token or pairing again unless you clear browser data or use a new device/browser.
When the token needs to be re-entered:
- Browser data / cookies / local storage cleared
- New browser or incognito window
- Different device
When device pairing approval is needed again:
- Same situations as above (clearing data generates a new device fingerprint)
- The server admin must SSH in and run the approve command each time
Security note
Section titled “Security note”OpenClaw is personal by default — it’s a single trust boundary. All paired users share the same agent permissions and tool access. For stricter multi-user setups, OpenClaw recommends separate gateway instances per user with isolated credentials. Fine for a small trusted team, but worth revisiting if more users are added.
Security
Section titled “Security”- Firewall (UFW): Ports 22, 80, 443 only
- Fail2ban: SSH brute force protection (sshd jail)
- Cloudflare: Edge SSL, DDoS protection (DNS proxied, orange cloud)
- SSL: Cloudflare Origin Certificate (wildcard
*.baseworks.com, expires 2041) - Auth layers: Cloudflare -> nginx Basic Auth -> OpenClaw gateway token -> device pairing
- Isolation: Separate VPS from n8n to limit blast radius if compromised
Gotchas / Lessons Learned
Section titled “Gotchas / Lessons Learned”- No pre-built Docker image — OpenClaw must be built from source (
docker build -t openclaw:local). Theopenclaw/openclaw:latestimage does not exist on Docker Hub. - Interactive onboarding — The
docker-setup.shscript requires interactive input. Can be bypassed by writingopenclaw.jsonmanually. - Config schema — Use
auth.mode(notauth.method),controlUi(notcontrolUI), andgateway.mode: "local"is required. - apiKey format — Use a plain string for the API key. The
{"env": "VAR_NAME"}shorthand doesn’t work; use{"source": "env", "provider": "...", "id": "..."}for env refs. - Device pairing — New browser connections require server-side approval via
devices approve <requestId>. - xCloud sudo — Servers provisioned via xCloud don’t have passwordless sudo. Add via xCloud custom command:
echo "patrick ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/patrick && chmod 440 /etc/sudoers.d/patrick - Cloudflare proxy — With DNS proxied (orange cloud), use Cloudflare Origin Certificates instead of Let’s Encrypt. Set SSL mode to Full (Strict).
Next Steps
Section titled “Next Steps”- Add messaging channels (Slack, Telegram, etc.)
- Configure agent identities and skills
- Connect OpenClaw to n8n via webhooks for the “hands” layer
- Build Vault Capture V2 (plan at
03-resources/agent-system/docs/Vault-Capture-V2-Plan.md) - Reactivate n8n workflows one by one, replacing CrewAI calls with OpenClaw
- Set up embedding provider for memory search (OPENAI_API_KEY, GEMINI_API_KEY, VOYAGE_API_KEY, or MISTRAL_API_KEY)