Your OpenClaw Docker Setup Is Exposed (Here's How to Check)
I Googled my server's IP address last Tuesday. My OpenClaw instance was the third result.
Not buried in some obscure database. Right there on Shodan. Port 3000. Open to the world. My agent's chat history visible to anyone who clicked.
I'd been running it for two months.
The Default Docker Compose Problem
OpenClaw's docker-compose.yml ships with sane defaults for local development. But "local development" and "production" are different planets.
Here's what a typical setup looks like:
services:
openclaw:
image: openclaw/openclaw:latest
ports:
- "3000:3000"
environment:
- ANTHROPIC_API_KEY=sk-ant-abc123...
- OPENAI_API_KEY=sk-proj-xyz789...
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Three problems in eight lines.
ports: "3000:3000" binds to 0.0.0.0. Every network interface. Every IP address on that machine. If your VPS has a public IP, congratulations: your OpenClaw dashboard is on the public internet.
Environment variables in plaintext. Your $200/month Anthropic key sitting in a .env file or inline in the compose file. One docker inspect and it's visible.
Docker socket mounted. Your agent can control Docker itself. It can start containers, read other containers' environment variables, or escape the sandbox entirely.
How to Check If You're Exposed Right Now
Takes 90 seconds. Do it now.
Check 1: Shodan
Go to shodan.io and search for your server's IP address. If you see port 3000 (or whatever port you mapped), your instance is public.
Search http.title:"OpenClaw" to see how many others made the same mistake. Last time I checked: hundreds.
Check 2: nmap from outside
From a different machine (your laptop, a friend's server, anything not on the same network):
nmap -p 3000,8080,443 YOUR_SERVER_IP
If port 3000 shows open, anyone on the internet can reach it.
Check 3: Check your Docker port bindings
SSH into your server and run:
docker ps --format "table {{.Names}} {{.Ports}}"
Look for 0.0.0.0:3000->3000/tcp. That 0.0.0.0 means "every interface." You want 127.0.0.1:3000->3000/tcp instead.
Check 4: Your .env file permissions
ls -la .env
stat -c "%a %U %G" .env
If it's world-readable (644), any process on the machine can read your API keys.
Running OpenClaw in production? These aren't edge cases. They're the default state of most deployments. Deploy securely with Clawctl →
The Fixes (If You Want to DIY)
Fix the port binding
Change your compose file to bind only to localhost:
ports:
- "127.0.0.1:3000:3000"
Then put a reverse proxy in front. Nginx or Caddy. With TLS.
server {
listen 443 ssl;
server_name openclaw.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/openclaw.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/openclaw.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Fix the API key storage
Never put keys directly in docker-compose.yml. Use Docker secrets or an external secrets manager.
At minimum, lock down the .env file:
chmod 600 .env
chown root:root .env
Fix the Docker socket
Replace the raw socket mount with a socket proxy that limits what the container can do:
services:
docker-proxy:
image: wollomatic/socket-proxy:1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- ALLOW_START=1
- ALLOW_STOP=1
- ALLOW_RESTARTS=1
Then point OpenClaw at tcp://docker-proxy:2375 instead of mounting the socket.
This is hours of configuration. And you still have to maintain it. For the full architecture, see our OpenClaw architecture breakdown.
What You're Still Missing
Even after those fixes, you don't have:
- Audit logs. What did the agent do at 3am? You don't know.
- Egress controls. Your agent can call any URL on the internet. Any API. Any webhook.
- Key rotation. Your API keys are static until you manually rotate them.
- Human approval flows. The agent runs every command without asking. See our approval workflows guide.
- Automated recovery. Container crashes at 2am? Hope you set up monitoring.
These aren't nice-to-haves. They're the gap between "running OpenClaw" and "running OpenClaw in production."
For more on what production security looks like, read our security risks breakdown or the production checklist. Want to know the full cost of fixing all this yourself? See the true cost of self-hosting.
Why Clawctl Exists
We built Clawctl because we got tired of doing all of this by hand.
Every Clawctl deployment ships with:
- TLS termination. No Nginx config needed.
- Encrypted API key storage. Keys never touch disk in plaintext.
- Docker socket proxy with per-tenant scoping.
- Audit logs for every agent action.
- Egress controls and network isolation.
- Auto-recovery if a container crashes.
The default is secure. Not "secure if you read the docs and do 14 extra steps."
Ready to stop worrying?
Clawctl locks down your OpenClaw instance in 60 seconds. Encrypted keys, audit logs, egress controls, human approvals. $49/mo. No contracts. Start now →