What Is OpenClaw & Why Self-Host?
OpenClaw is the Claude-focused content and automation layer inside the Outclaw ecosystem. Think of it as the engine that runs Claude-powered workflows, newsletter automations, API integrations, and content pipelines — all built around the Anthropic Claude API. While you can use OpenClaw through the managed Outclaw platform, self-hosting gives you three meaningful advantages.
Prerequisites & What You'll Need
Before touching a terminal, collect these. Missing any of them mid-setup is the #1 reason people stall.
| Item | Details | Where to Get It |
|---|---|---|
| Anthropic API Key | Required for all Claude model calls. Starts with sk-ant- |
console.anthropic.com |
| Node.js 20+ | OpenClaw's runtime. LTS release preferred. | nodejs.org or nvm |
| Git | For cloning the OpenClaw repo and pulling updates. | Pre-installed on most systems |
| VPS or Mac Mini | 2 GB RAM minimum. 4 GB recommended for parallel workflows. | DigitalOcean, Hetzner, Vultr, or local hardware |
| Domain (optional) | Needed only if you want HTTPS and a public URL for VPS hosting. | Namecheap, Cloudflare Registrar, etc. |
| PM2 | Process manager for keeping OpenClaw alive. Installed via npm. | npm install -g pm2 |
VPS Setup (Ubuntu 24.04)
This section assumes you've just spun up a fresh Ubuntu 24.04 LTS droplet, Linode, or Hetzner VPS. We'll go from a bare root shell to a running OpenClaw instance with Nginx reverse proxy and SSL. Each command block is copy-paste ready.
Step 1 — Initial server hardening
SSH into your new server as root, then run the following to update, create a deploy user, and lock down the firewall.
# Update system packages apt update && apt upgrade -y # Create a non-root deploy user adduser deploy usermod -aG sudo deploy # Copy your SSH key to the new user rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy # Configure UFW firewall — allow SSH, HTTP, HTTPS ufw allow OpenSSH ufw allow 'Nginx Full' ufw enable # Switch to the deploy user for the rest of setup su - deploy
Step 2 — Install Node.js 20 via nvm
Using nvm means you can switch Node versions per project and avoid sudo npm headaches later.
# Install nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # Reload shell to activate nvm source ~/.bashrc # Install and use Node 20 LTS nvm install 20 nvm use 20 nvm alias default 20 # Verify node -v # should output v20.x.x npm -v # should output 10.x.x
Step 3 — Clone OpenClaw & install dependencies
# Clone the OpenClaw repository git clone https://github.com/openclaw/openclaw.git ~/openclaw cd ~/openclaw # Install production dependencies npm install --production # Copy the example environment config cp .env.example .env
Step 4 — Configure your environment variables
Open .env with your preferred editor (nano .env) and fill in the required values.
# ── Required ──────────────────────────────── ANTHROPIC_API_KEY=sk-ant-api03-YOUR_KEY_HERE # Claude model to use by default CLAUDE_MODEL=claude-sonnet-4-6 # Server port (Nginx will proxy to this) PORT=3000 # ── Optional: for MCP integrations ────────── SUPABASE_URL=https://your-project.supabase.co SUPABASE_ANON_KEY=your-supabase-anon-key # Webhook secret for inbound triggers WEBHOOK_SECRET=a-long-random-string-here # ── Production ────────────────────────────── NODE_ENV=production
.gitignore already excludes it, but double-check: cat .gitignore | grep .env. If you see .env listed, you're safe.Step 5 — Set up Nginx as a reverse proxy
Nginx sits in front of OpenClaw, handles SSL termination, and routes traffic on port 80/443 to your Node process on port 3000. Install Nginx, then create the site config.
sudo apt install nginx -y sudo nano /etc/nginx/sites-available/openclaw
Paste the following into the Nginx config file. Replace your-domain.com with your actual domain (or your VPS IP if you're skipping DNS).
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:3000;
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_cache_bypass $http_upgrade;
proxy_read_timeout 120s;
}
}
# Enable the site config sudo ln -s /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/ # Test config syntax sudo nginx -t # Reload Nginx sudo systemctl reload nginx # Install Certbot for free SSL (requires DNS pointing to this IP) sudo apt install certbot python3-certbot-nginx -y sudo certbot --nginx -d your-domain.com
http://YOUR_VPS_IP:3000 after starting OpenClaw. You can add SSL later with Certbot when you're ready to go public.Mac Mini Setup (macOS 15)
A Mac Mini (M2 or M4) running macOS 15 Sequoia is an excellent self-hosting option — always-on, silent, power-efficient, and you've likely already got one. The setup is faster than the VPS path since macOS ships with some tools pre-installed.
- No hardware investment upfront
- Publicly accessible URL by default
- Easy to scale or snapshot
- Runs independently of your home network
- $5–20/month ongoing cost
- Shared hardware (noisy neighbours)
- Zero ongoing cost if you already own it
- Apple Silicon is fast for local inference
- Full hardware control and privacy
- Combine with ngrok/Cloudflare Tunnel for public access
- Depends on home internet uptime
- Needs manual IP/tunnel config for public URLs
Step 1 — Install Homebrew & Node.js
# Install Homebrew if not already present /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # Install Node.js 20 via Homebrew brew install node@20 # Add Node 20 to your PATH (Apple Silicon path) echo 'export PATH="/opt/homebrew/opt/node@20/bin:$PATH"' >> ~/.zshrc source ~/.zshrc # Verify node -v # v20.x.x
Step 2 — Clone OpenClaw
# Clone into your home directory git clone https://github.com/openclaw/openclaw.git ~/openclaw cd ~/openclaw # Install dependencies npm install # Create your .env file cp .env.example .env nano .env # or open with VS Code: code .env
Fill in ANTHROPIC_API_KEY and PORT=3000 at minimum. The same env config from Section 03 applies here exactly.
Step 3 — Allow incoming connections on macOS
macOS Firewall can block OpenClaw's port. If you plan to access it from other devices on your network, open System Settings and allow the connection.
# Check if the firewall is enabled sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate # If enabled, add Node to allowed apps sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add $(which node) sudo /usr/libexec/ApplicationFirewall/socketfilterfw --unblockapp $(which node)
Step 4 (optional) — Public access via Cloudflare Tunnel
If you want your Mac Mini OpenClaw instance accessible from outside your home network without port-forwarding your router, Cloudflare Tunnel is the cleanest solution. It's free for personal use.
# Install cloudflared brew install cloudflare/cloudflare/cloudflared # Authenticate (opens browser) cloudflared tunnel login # Create a tunnel cloudflared tunnel create openclaw # Run the tunnel pointing to localhost:3000 cloudflared tunnel run --url http://localhost:3000 openclaw # Cloudflare will give you a *.trycloudflare.com URL # Connect it to your own domain in the Cloudflare dashboard
http://mac-mini-local-ip:3000. You can get your Mac Mini's local IP from System Settings → Network.Connecting the Claude API
OpenClaw communicates with Anthropic's API using the @anthropic-ai/sdk package. If you followed Sections 03 or 04, the SDK is already installed as a dependency. This section explains how the connection works and how to verify it's healthy.
Verify your API key works
Before starting OpenClaw, run this one-liner to confirm your key is valid and the Anthropic endpoint is reachable from your server:
curl https://api.anthropic.com/v1/messages \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "max_tokens": 64, "messages": [{"role": "user", "content": "Reply OK"}] }' # Expected: {"content":[{"type":"text","text":"OK"}], ...} # If you see {"error": ...}, check your API key in .env
Model selection in OpenClaw
OpenClaw supports switching Claude models per workflow. The CLAUDE_MODEL env var sets the default, but individual workflow configs can override it. Here's the model matrix for 2026:
| Model | Speed | Best For | .env value |
|---|---|---|---|
| claude-haiku-4-5 | Fastest | High-volume classification, summaries, routing | claude-haiku-4-5-20251001 |
| claude-sonnet-4-6 | Fast | Default workhorse — writing, analysis, code, workflows | claude-sonnet-4-6 |
| claude-opus-4-6 | Slower | Complex multi-step reasoning, long-form research tasks | claude-opus-4-6 |
claude-sonnet-4-6 as your default. It handles 90%+ of OpenClaw workflows well. Upgrade specific workflows to Opus when you actually need deeper reasoning — don't default to Opus globally.MCP Workflow Integrations
Model Context Protocol (MCP) lets OpenClaw connect Claude directly to external services — your database, email, calendar, CRM — giving it real-time context and write access. This is where self-hosted OpenClaw earns its keep versus a managed platform.
Configuring an MCP server in openclaw.config.js
OpenClaw reads MCP server definitions from openclaw.config.js in the project root. Add each integration as a server object in the mcp_servers array:
// openclaw.config.js module.exports = { model: process.env.CLAUDE_MODEL || 'claude-sonnet-4-6', max_tokens: 4096, mcp_servers: [ { type: 'url', name: 'supabase', url: 'https://mcp.supabase.com/mcp', }, { type: 'url', name: 'gmail', url: 'https://gmail.mcp.claude.com/mcp', }, { // Custom local MCP server example type: 'url', name: 'my-custom-crm', url: 'http://localhost:4000/mcp', }, ], };
npm run mcp:auth and follow the browser prompts. Tokens are stored in ~/.openclaw/tokens.json.Process Management & Auto-Restart
Running OpenClaw with a raw node index.js means it dies the moment your SSH session closes or the process crashes. PM2 keeps it alive, restarts it on crash, and boots it on server reboot. This step applies identically to VPS and Mac Mini.
# Install PM2 globally npm install -g pm2 # Start OpenClaw with PM2 (from the openclaw directory) cd ~/openclaw pm2 start npm --name "openclaw" -- start # Check status pm2 status # Tail live logs pm2 logs openclaw # Enable startup on reboot (follow the printed command) pm2 startup pm2 save
Useful PM2 commands to bookmark
| Command | What it does |
|---|---|
pm2 restart openclaw |
Restart the OpenClaw process (zero-downtime in cluster mode) |
pm2 stop openclaw |
Stop the process without removing it from PM2's list |
pm2 delete openclaw |
Remove from PM2 entirely (re-run start to re-add) |
pm2 logs openclaw --lines 100 |
Print the last 100 log lines |
pm2 monit |
Live terminal dashboard: CPU, memory, log stream |
pm2 reload openclaw |
Graceful reload — useful after updating .env or config |
git pull), run npm install to catch any new deps, then pm2 reload openclaw. PM2 handles the graceful restart — no downtime.Troubleshooting & Common Errors
These are the errors that trip up 80% of new installs. Before opening an issue on GitHub, check this list.
Your
ANTHROPIC_API_KEY in .env is wrong, expired, or has a trailing space. Open .env, remove any whitespace around the key value, and run the smoke test curl from Section 05. Also confirm the key is active in console.anthropic.com.
Something else is running on port 3000. Find and kill it:
lsof -ti:3000 | xargs kill -9, then restart OpenClaw. Or change PORT=3001 in your .env and update your Nginx proxy config to match.
Nginx is running but OpenClaw isn't. Check:
pm2 status — is OpenClaw showing "online"? If not, check logs with pm2 logs openclaw. The most common cause is a missing .env file or a Node version mismatch.
OAuth token may have expired. Run
npm run mcp:auth again for the affected server. For local MCP servers, ensure they're running (pm2 status) and that the URL in openclaw.config.js matches the actual port.
nvm-managed Node isn't in the PATH when PM2 starts at boot. Fix: use
which node to find the absolute path, then update your PM2 startup script to use it: pm2 start /opt/homebrew/opt/node@20/bin/node -- index.js --name openclaw.
Run cloudflared as a persistent service:
sudo cloudflared service install. This registers it as a launchd daemon on macOS or systemd service on Linux so it auto-restarts on crash and survives reboots.
Still stuck?
Run pm2 logs openclaw --lines 200 and copy the last 50 lines. Paste into the #openclaw-support channel in the Outclaw community Discord, along with your OS and Node version (node -v). The community resolves most issues within a few hours.