OpenClaw Codex

Recipe

Deploy OpenClaw on a VPS

From zero to a production-ready OpenClaw gateway on an Ubuntu/Debian VPS. Covers Node.js via nvm, global npm install, systemd service, secrets management, and optional Cloudflare Tunnel for secure public access — all in about 20 minutes.

Prerequisites

  • A VPS running Ubuntu 22.04+ or Debian 12+ (1 CPU / 2 GB RAM minimum)
  • SSH access with root or a sudo user
  • An API key from at least one LLM provider (OpenAI, Anthropic, Google, Minimax, etc.)
  • A domain name (optional, for Cloudflare Tunnel)

Step 1 — Install Node.js via nvm

OpenClaw requires Node.js 22+. We use nvm so you can manage versions independently of your OS packages.

bash Install nvm + Node.js 22
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc

# Install and use Node.js 22 (LTS)
nvm install 22
nvm alias default 22
node --version   # should print v22.x.x

Step 2 — Install OpenClaw

Install the OpenClaw gateway globally via npm.

bash Global install
npm install -g openclaw

Verify the install:

bash
openclaw --version
# Expected: openclaw v2026.x.x

Step 3 — Configure Secrets

Create a secrets environment file. This keeps API keys out of your service unit and shell history.

bash ~/.config/openclaw/secrets.env
mkdir -p ~/.config/openclaw

cat > ~/.config/openclaw/secrets.env << 'EOF'
# === LLM Provider Keys ===
OPENAI_API_KEY=sk-your-openai-key-here
ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here
GOOGLE_GENERATIVE_AI_API_KEY=your-google-key-here

# === Optional: Alternative Providers ===
# MINIMAX_API_KEY=your-minimax-key-here
# DEEPSEEK_API_KEY=your-deepseek-key-here

# === Channel Secrets (add as needed) ===
# FEISHU_APP_ID=your-feishu-app-id
# FEISHU_APP_SECRET=your-feishu-secret
# WECOM_CORP_ID=your-wecom-corp-id
EOF

chmod 600 ~/.config/openclaw/secrets.env

⚠️ Security: Never commit secrets.env to version control. Add it to .gitignore if your config directory is tracked.

Step 4 — Create a systemd Service

Run OpenClaw as a managed service with auto-restart and proper logging.

bash User-level systemd unit
# Create the service directory
mkdir -p ~/.config/systemd/user

# Write the service unit
cat > ~/.config/systemd/user/openclaw-gateway.service << 'EOF'
[Unit]
Description=OpenClaw Gateway
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=%h/.nvm/versions/node/v22.22.0/bin/node \
           %h/.nvm/versions/node/v22.22.0/lib/node_modules/openclaw/dist/entry.js \
           gateway --port 18789
EnvironmentFile=%h/.config/openclaw/secrets.env
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target
EOF

# Enable and start
systemctl --user daemon-reload
systemctl --user enable openclaw-gateway
systemctl --user start openclaw-gateway

# Verify
systemctl --user status openclaw-gateway

Tip: Replace v22.22.0 with your actual Node version from node --version.

Step 5 — Verify It's Running

bash Health check
# Check status
curl -s http://127.0.0.1:18789/status | head -20

# Check logs
journalctl --user -u openclaw-gateway -f --no-pager -n 50

You should see the gateway responding and model routes available. If you see errors about API keys, double-check your secrets.env.

Step 6 — (Optional) Cloudflare Tunnel

Expose your gateway to the internet without opening ports or setting up a reverse proxy. This is the simplest way to connect messaging channels like Feishu or WeCom that require webhook URLs.

bash Quick tunnel (no domain needed)
# Install cloudflared
curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 \
  -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared

# Start a quick tunnel (gives you a temporary URL)
cloudflared tunnel --url http://127.0.0.1:18789 --no-autoupdate

For a permanent tunnel with your own domain, see the Cloudflare Tunnel docs.

Step 7 — Management Script

Create a helper script for day-to-day operations.

bash manage_openclaw.sh
cat > ~/manage_openclaw.sh << 'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail
case "${1:-help}" in
  start)   systemctl --user start  openclaw-gateway ;;
  stop)    systemctl --user stop   openclaw-gateway ;;
  restart) systemctl --user restart openclaw-gateway ;;
  status)  systemctl --user status  openclaw-gateway ;;
  logs)    journalctl --user -u openclaw-gateway -f --no-pager -n "${2:-100}" ;;
  update)  npm update -g openclaw && systemctl --user restart openclaw-gateway ;;
  *)       echo "Usage: $0 {start|stop|restart|status|logs|update}" ;;
esac
SCRIPT
chmod +x ~/manage_openclaw.sh

Usage: ./manage_openclaw.sh restart, ./manage_openclaw.sh logs 50, ./manage_openclaw.sh update.

What's Next?