Problem: OpenClaw's Default Setup Exposes Your Credentials
You want to run OpenClaw for AI automation, but the default installation stores API keys in plaintext and runs with excessive privileges — creating a direct path to credential theft and system compromise.
You'll learn:
- Deploy OpenClaw in an isolated Docker environment
- Implement proper secret management (no plaintext keys)
- Harden network access and container permissions
- Monitor for security violations in real-time
Time: 45 min | Level: Advanced
Why This Matters (The Security Context)
In January 2026, security researchers discovered OpenClaw stores credentials in plaintext configuration files, making them trivial to steal. Over 42,000 exposed instances were found publicly accessible, and CVE-2026-25253 allowed one-click remote code execution via token exfiltration.
Common attack vectors:
- Plaintext API keys in
~/.openclaw/config.json - Prompt injection through email/web content
- Malicious skills from ClawHub marketplace (7% contain credential leaks)
- Cross-site WebSocket hijacking (patched in v2026.1.29+)
Why private cloud deployment helps: Running on your own infrastructure (not your laptop) isolates the attack surface. Combined with proper hardening, you get AI automation without risking your primary systems.
Prerequisites
Required:
- Linux server (Ubuntu 24.04+ recommended) or VPS
- Docker Engine 24.0+ with Docker Compose v2
- 2GB RAM minimum ($24/month VPS tier)
- Domain name (optional, for TLS)
Security tools needed:
# Install Docker if not present
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Verify versions
docker --version # Should be 24.0+
docker compose version # Should be v2.x
Anthropic API key: Get one at https://console.anthropic.com/settings/keys (OpenClaw works best with Claude Sonnet 4.5)
Solution: Security-Hardened Deployment
Step 1: Clone and Prepare Environment
# Clone OpenClaw repository
git clone https://github.com/openclaw/openclaw.git
cd openclaw
# Checkout latest stable version (avoid bleeding edge)
git checkout tags/v2026.1.30
# Create isolated workspace
mkdir -p ~/openclaw-workspace
chmod 700 ~/openclaw-workspace # Restrict permissions
Why this works: Using tagged releases avoids unstable main branch builds. The 700 permission ensures only your user can access the workspace.
Expected: You should see openclaw/ directory with Dockerfile and docker-compose.yml
Step 2: Configure Secret Management
DO NOT store API keys in config files. Use environment variables instead.
# Create secrets file (never commit this)
cat > .env.secrets << 'EOF'
# Anthropic API Key
ANTHROPIC_API_KEY=sk-ant-your-key-here
# Gateway authentication token (generate random)
OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
# Disable localhost trust (critical)
LOCALHOST_TRUST_ENABLED=false
GATEWAY_AUTH_MODE=token
EOF
# Secure the secrets file
chmod 600 .env.secrets
Security note: The LOCALHOST_TRUST_ENABLED=false prevents the CVE-2026-25253 vulnerability. Always generate a unique gateway token.
Step 3: Create Hardened Docker Compose Configuration
Create docker-compose.hardened.yml:
version: '3.8'
services:
openclaw-gateway:
image: openclaw/gateway:v2026.1.30
container_name: openclaw-gateway
# Security hardening
security_opt:
- no-new-privileges:true # Prevent privilege escalation
cap_drop:
- ALL # Drop all capabilities
cap_add:
- NET_BIND_SERVICE # Only allow binding to ports
# Run as non-root user
user: "1000:1000"
# Read-only root filesystem
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=100M
# Environment from secrets file
env_file:
- .env.secrets
environment:
- NODE_ENV=production
- GATEWAY_AUTH_MODE=token
- LOCALHOST_TRUST_ENABLED=false
# Volume mounts (minimal)
volumes:
- openclaw-config:/home/openclaw/.openclaw:rw
- ~/openclaw-workspace:/workspace:rw
# Network isolation
networks:
- openclaw-internal
# Resource limits
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
memory: 512M
# Health check
healthcheck:
test: ["CMD", "node", "-e", "process.exit(0)"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
# Reverse proxy with TLS (optional but recommended)
nginx:
image: nginx:alpine
container_name: openclaw-nginx
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro # If using certbot
networks:
- openclaw-internal
depends_on:
- openclaw-gateway
restart: unless-stopped
networks:
openclaw-internal:
driver: bridge
internal: true # No external access except through nginx
volumes:
openclaw-config:
driver: local
What this does:
- Runs container as non-root user (UID 1000)
- Drops all Linux capabilities except network binding
- Read-only filesystem prevents malicious writes
- Internal network isolates from internet
- Resource limits prevent DoS attacks
Step 4: Configure Nginx Reverse Proxy (Optional TLS)
Create nginx.conf:
events {
worker_connections 1024;
}
http {
# Rate limiting to prevent abuse
limit_req_zone $binary_remote_addr zone=openclaw:10m rate=10r/s;
upstream openclaw {
server openclaw-gateway:18789;
}
server {
listen 443 ssl http2;
server_name your-domain.com; # Replace with your domain
# TLS configuration (use certbot to generate certs)
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# Modern TLS only
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
# WebSocket support for OpenClaw gateway
location / {
limit_req zone=openclaw burst=20 nodelay;
proxy_pass http://openclaw;
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;
# Prevent token exfiltration (CVE-2026-25253 mitigation)
proxy_set_header Origin "";
}
}
}
If not using TLS: Remove the nginx service and expose port 18789 directly (not recommended for production).
Step 5: Firewall Configuration
# Allow only SSH and HTTPS
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH
sudo ufw allow 443/tcp # HTTPS (if using nginx)
sudo ufw enable
# Verify rules
sudo ufw status verbose
Expected output:
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
If it fails:
- Error: "Command not found": Install ufw with
sudo apt install ufw - SSH locked out: Add your IP specifically:
sudo ufw allow from YOUR_IP to any port 22
Step 6: Launch OpenClaw Gateway
# Start services
docker compose -f docker-compose.hardened.yml up -d
# Check logs for errors
docker compose logs -f openclaw-gateway
# You should see: "Gateway started on port 18789"
Get dashboard access:
docker compose exec openclaw-gateway node cli.js dashboard --no-open
Expected: You'll see a URL with a token like:
http://127.0.0.1:18789/?token=abc123...
Access this via your domain if using nginx: https://your-domain.com/?token=abc123...
Step 7: Pair Messaging Platforms (Telegram Example)
OpenClaw integrates with WhatsApp, Telegram, Slack, and others. Telegram is most secure for private cloud.
# Enter the container
docker compose exec openclaw-gateway sh
# Run onboarding
node cli.js onboard
# Select: Telegram
# Paste your Telegram bot token from @BotFather
# Complete device pairing
Security tip: Create a dedicated Telegram bot for OpenClaw — never use your personal account credentials.
Verification
Test 1: Confirm No Plaintext Secrets
# Check that API keys are NOT in config files
docker compose exec openclaw-gateway sh -c "grep -r 'sk-ant' /home/openclaw/.openclaw/ || echo 'No plaintext keys found'"
You should see: No plaintext keys found
Test 2: Verify Container Isolation
# Attempt to write to root filesystem (should fail)
docker compose exec openclaw-gateway sh -c "touch /test.txt 2>&1 || echo 'Filesystem is read-only (correct)'"
Expected: Filesystem is read-only (correct)
Test 3: Test Gateway Authentication
# Try connecting without token (should fail)
curl https://your-domain.com/api/health
# Expected: 401 Unauthorized or connection refused
Production Checklist
Before using OpenClaw with real credentials:
- Secrets stored in environment variables (NOT config files)
- Container runs as non-root user
- Firewall allows only necessary ports (22, 443)
- TLS enabled with valid certificate
-
LOCALHOST_TRUST_ENABLED=falsein environment - Gateway token is randomly generated (32+ chars)
- OpenClaw version is 2026.1.29 or newer (CVE patched)
- Read-only filesystem enabled
- Resource limits configured
- No ClawHub skills installed (vet thoroughly first)
What You Learned
- Private cloud deployment isolates OpenClaw from your primary systems
- Docker hardening (non-root, read-only, dropped caps) prevents container breakout
- Secret management via environment variables eliminates plaintext credential theft
- Network isolation + reverse proxy creates defense in depth
Critical limitation: OpenClaw's security model is still maturing. Even hardened deployments can be vulnerable to:
- Prompt injection via email/web content
- Malicious ClawHub skills (26% analyzed in late 2025 had vulnerabilities)
- LLM hallucinations causing unintended actions
Do NOT use for:
- Production systems with critical data access
- Corporate environments without explicit security approval
- Machines with sensitive credentials already stored
Advanced: Monitoring for Security Violations
Add monitoring to detect suspicious activity:
# Add to docker-compose.hardened.yml
promtail:
image: grafana/promtail:latest
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
networks:
- openclaw-internal
Create promtail-config.yml:
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: openclaw
docker_sd_configs:
- host: unix:///var/run/docker.sock
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(openclaw-gateway)'
action: keep
# Alert on suspicious patterns
pipeline_stages:
- match:
selector: '{job="openclaw"}'
stages:
- regex:
expression: '(?i)(sk-ant|sk-|password|token|secret)'
- labels:
alert: credential_leak
What this monitors: Any log output containing API keys or secrets triggers an alert, indicating potential credential exfiltration.
Troubleshooting
"Gateway disconnected (1008): pairing required"
Cause: Gateway token expired or browser not authenticated.
Fix:
docker compose exec openclaw-gateway node cli.js dashboard --no-open
# Get new URL with fresh token
Container exits with "Permission denied"
Cause: Volume mounts have wrong ownership.
Fix:
# Set correct ownership (assuming UID 1000)
sudo chown -R 1000:1000 ~/openclaw-workspace
docker compose -f docker-compose.hardened.yml restart
"Cannot connect to Anthropic API"
Cause: Network isolation preventing outbound connections.
Fix: Modify docker-compose.hardened.yml network:
networks:
openclaw-internal:
driver: bridge
internal: false # Allow outbound (but still isolated from host)
Then restart:
docker compose -f docker-compose.hardened.yml down
docker compose -f docker-compose.hardened.yml up -d
Cost Breakdown
VPS hosting (minimum specs):
- DigitalOcean Droplet: $24/month (2GB RAM, 1 CPU)
- Hetzner Cloud: ~$5/month (2GB RAM equivalent in EU)
- Linode: $12/month (2GB shared CPU)
API costs:
- Anthropic Claude Sonnet 4.5: ~$3/million input tokens
- Typical usage: $10-50/month for personal automation
Total: $30-75/month for production-ready private AI agent
Tested on Ubuntu 24.04, Docker 25.0.1, OpenClaw v2026.1.30
Security disclaimer: This guide implements current best practices as of February 2026. OpenClaw is rapidly evolving software with ongoing security discoveries. Always review the latest security advisories at https://docs.openclaw.ai/security/advisories before deploying to production.
Report vulnerabilities: If you discover security issues, follow responsible disclosure at https://github.com/openclaw/openclaw/security/policy