Setup Guide · March 2026

OpenClaw on a VPS
& Mac Mini

⏱ ~25 min setup
🎯 Intermediate
🐧 Ubuntu 24.04 + macOS 15

The definitive walkthrough for self-hosting OpenClaw — Outclaw's Claude-powered content layer — on either a cloud VPS or a local Mac Mini. No hand-waving. No skipped steps. From zero to a running server with a working Anthropic API connection, persistent process management, and optional MCP workflow integrations.

Ubuntu 24.04 macOS Sequoia 15 Node.js 20+ Claude API Nginx Reverse Proxy PM2 MCP Server
On This Page

Jump to any section

01
What Is OpenClaw & Why Self-Host?
02
Prerequisites & What You'll Need
03
VPS Setup (Ubuntu 24.04)
04
Mac Mini Setup (macOS 15)
05
Connecting the Claude API
06
MCP Workflow Integrations
07
Process Management & Auto-Restart
08
Troubleshooting & Common Errors
Section 01

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.

🔒
Full Data Control
Your prompts, outputs, and workflow configs never touch a third-party server. Everything routes through your own infrastructure before hitting the Anthropic API.
Zero Rate-Limit Sharing
On a shared platform you share throughput with other users. Self-hosted means your Anthropic API key has the lane to itself — critical for high-volume automations.
🔧
Custom MCP Integrations
The managed platform limits which MCP servers you can wire in. Self-hosted OpenClaw lets you connect any Model Context Protocol server — Supabase, Linear, custom databases, anything.
💸
Cost Transparency
You pay Anthropic directly. A $5/mo VPS or an M2 Mac Mini you already own beats any subscription pricing at meaningful usage volumes.
🌐
Always-On Availability
A properly configured VPS or local server runs 24/7, meaning scheduled automations and API webhooks don't depend on your laptop being awake.
🧪
Dev & Prod Environments
Spin up separate dev and production instances, test new Claude models before they hit your live workflows, and roll back easily — impossible on a managed plan.
ℹ️
VPS vs Mac Mini: Both paths produce an identical running server. The difference is operational: a VPS costs ~$5–12/month and runs in a datacenter; a Mac Mini costs nothing ongoing if you already own one and gives you local hardware for testing. This guide covers both in full. Jump to Section 03 or Section 04 depending on your path.
Section 02

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
⚠️
API key billing: Your Anthropic API key is billed per token. OpenClaw's default config is conservative, but if you enable high-frequency automations, set a usage cap in the Anthropic console before you start. Go to console.anthropic.com → Billing → Usage limits.
Section 03

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.

01
Provision Server
Spin up Ubuntu 24.04 LTS. Choose at least 2 GB RAM. Add your SSH key during provisioning — don't use password auth.
02
Harden & Update
Update packages, create a non-root user, configure UFW firewall. Running as root is a bad idea for a persistent server.
03
Install Stack & Deploy
Install Node 20, clone OpenClaw, wire the Anthropic API key, configure Nginx, and launch with PM2.

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.

bash · Initial server setup
# 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.

bash · Node.js via nvm
# 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

bash · Clone & install
# 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.

.env · Environment config
# ── 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
⚠️
Never commit your .env file. The repo's .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.

bash · Install Nginx
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).

nginx · sites-available/openclaw
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;
    }
}
bash · Enable site & obtain SSL cert
# 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
💡
Skipping SSL for now? Totally fine for internal use. Just point your browser to http://YOUR_VPS_IP:3000 after starting OpenClaw. You can add SSL later with Certbot when you're ready to go public.
Section 04

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.

☁️ VPS
Cloud Server
  • 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)
🖥️ Mac Mini
Local Hardware
  • 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

zsh · macOS terminal
# 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

zsh · Clone & configure
# 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.

zsh · Allow port via macOS firewall
# 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.

zsh · Cloudflare Tunnel setup
# 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
💡
Keep it simple: For a private Mac Mini setup (just you and your network), skip Cloudflare Tunnel entirely. Access OpenClaw at http://mac-mini-local-ip:3000. You can get your Mac Mini's local IP from System Settings → Network.
Section 05

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:

bash/zsh · Quick API smoke test
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
💡
Cost tip: Start with 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.
Section 06

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.

🗄️
Supabase MCP
Connect Claude to your Supabase Postgres database. Query rows, insert records, and run migrations via natural language workflow prompts.
📧
Gmail MCP
Wire Gmail so Claude can read, draft, and send email from within OpenClaw workflows. Useful for newsletter automation and outreach pipelines.
📅
Google Calendar MCP
Give Claude calendar access for scheduling-aware workflows — auto-book slots, summarise week-ahead context, draft meeting prep docs.
🚀
Vercel MCP
Trigger deployments, check build logs, and manage preview environments from OpenClaw workflows. Pair with GitHub for a full CI assistant.
📊
PostHog MCP
Pull product analytics into your Claude workflows. Generate insight summaries, spot anomalies, and auto-draft analysis reports on a schedule.
🔗
Custom MCP Servers
Build your own MCP server in Node.js and wire it to OpenClaw. Any REST API can become an MCP tool Claude can call mid-workflow.

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:

js · openclaw.config.js
// 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',
    },
  ],
};
ℹ️
OAuth-based MCP servers (Gmail, Google Calendar, Vercel) require a one-time OAuth authentication flow. After adding them to your config, run npm run mcp:auth and follow the browser prompts. Tokens are stored in ~/.openclaw/tokens.json.
Section 07

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.

bash/zsh · PM2 setup
# 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
💡
Deploying updates: When you pull new code (git pull), run npm install to catch any new deps, then pm2 reload openclaw. PM2 handles the graceful restart — no downtime.
Section 08

Troubleshooting & Common Errors

These are the errors that trip up 80% of new installs. Before opening an issue on GitHub, check this list.

🔴
Error: Invalid API key · 401 Unauthorized
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.
🔴
EADDRINUSE: address already in use :::3000
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.
🔴
502 Bad Gateway (Nginx)
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.
🔴
MCP connection refused / timeout
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.
🔵
Mac Mini: node not found after reboot
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.
🔵
Cloudflare Tunnel drops intermittently
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.

Get the alpha in
your inbox.

Every Tuesday: Claude workflows, API deep-dives, and the OpenClaw updates your feed won't surface. 8 minutes. Zero filler.

Subscribe to OutClaw AI →