← Articles

OpenClaw on a VPS: Production-Grade Setup Guide

By the end of this guide, your OpenClaw instance will:

This guide assumes a clean Ubuntu VPS. If you previously installed OpenClaw incorrectly (for example, under the root user), jump to the Reset a Broken Installation section at the end before continuing.

Getting a Ubuntu VPS

There are many options:

You only need 8GB and I paid $5 USD / month for mine at Contabo which has a dedicated site for Openclaw users.


Architecture Overview

Before diving in, it helps to understand how all the pieces fit together.

WhatsApp ──► OpenClaw Gateway ──► OpenRouter (LLM)


              Skills Layer
         ┌─────────┬──────────┬──────────────┬──────────┐
         │         │          │              │          │
       Gmail    GitHub     Brave Search   Obsidian   (more)
    (Himalaya)  (gh CLI)

OpenClaw’s gateway is the always-running process that listens for WhatsApp messages and routes them to a language model. The skills layer is a collection of CLI tools (like GitHub’s gh or Himalaya for email) that OpenClaw can call to take real-world actions.

OpenClaw runs as a systemd user service — not as root. That distinction matters, and we’ll explain why as we go.


1. Create a Secure Runtime User

Never run OpenClaw as root!

Root is the most powerful account on a Linux system. It can read, write, or delete anything, including system files. If an AI agent ever executes a bad command as root, the consequences can be catastrophic (think: wiped server). Running OpenClaw as a regular user limits the damage any mistake can cause.

SSH into your server as root and create a dedicated user:

ssh root@YOUR_SERVER_IP
adduser openclaw
usermod -aG sudo openclaw

What these do:

Now switch to that user:

su - openclaw

The - flag loads a full login environment for the user, including their shell settings and PATH.


1.1 Configure the npm Global Prefix

Before installing anything with npm, you need to fix a permission problem that trips up almost everyone.

The problem: When you run npm install -g (the -g means “install globally, for all users”), npm tries to write to /usr/lib/node_modules/, a directory owned by root. Since you’re now operating as the openclaw user, you don’t have permission to write there. You’ll see an error like:

npm error code EACCES
npm error syscall mkdir
npm error path /usr/lib/node_modules/openclaw

The fix: Tell npm to install global packages inside your home directory instead, where you do have write access.

mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

What each line does:


2. Install OpenClaw

With npm configured correctly, install the OpenClaw CLI:

npm install -g openclaw
openclaw --version

You should see something like 2026.2.13. If the command isn’t found, double-check that ~/.npm-global/bin is in your PATH by running echo $PATH.

Run the Onboarding Wizard

openclaw onboard --install-daemon

The --install-daemon flag tells the wizard to also set up a background service. Work through the prompts using these recommended selections:

PromptSelection
Onboarding modeQuickStart
ChannelWhatsApp
Phone setupPersonal phone number
WhatsApp numberYour number (e.g. +52XXXXXXXX)
Configure skillsYes
Skills to installclawhub, github, gog, mcporter, obsidian
Node managernpm
Hookssession-memory
DM policyallowlist

Scan the WhatsApp QR Code

During onboarding, a QR code will appear in your terminal. On your phone:

  1. Open WhatsApp → SettingsLinked DevicesLink a Device
  2. Scan the QR code

After pairing, OpenClaw will restart the connection and you’ll see a code like 515 in the logs. This is expected and normal, it means the WhatsApp session was successfully re-established after pairing. Nothing is broken.

Note: Some skills (like github and gog) may fail during this first install because they depend on Homebrew, which you haven’t installed yet. No worries, you’ll reinstall them in Step 6.


3. Configure the LLM Provider

OpenClaw needs a language model to power its intelligence. We’ll use OpenRouter, which gives you access to many models through a single API.

openclaw configure --section model

When prompted:

Then add your OpenRouter API key to OpenClaw’s environment file:

echo 'OPENROUTER_API_KEY=sk-or-xxxxxxxx' >> ~/.openclaw/.env

Replace sk-or-xxxxxxxx with your actual key from openrouter.ai.

What is .env? It’s a plain text file that stores environment variables, named values that programs can read. Keeping secrets like API keys here is a standard security practice.


Enable Brave Search so OpenClaw can look things up on the web:

openclaw configure --section web

You can get a free Brave Search API key at brave.com/search/api.


5. Make It Persistent (Systemd Setup)

By default, OpenClaw’s gateway process stops when you close your SSH session. To make it run 24/7, we use systemd — Linux’s built-in system for managing long-running processes.

What is systemd?

Systemd is the “init system” on modern Linux. It starts processes when the server boots, restarts them if they crash, and manages their logs. Services managed by systemd are called units.

There are two kinds of systemd units:

OpenClaw uses a user unit. That means it runs as the openclaw user, with only that user’s permissions.

Enable Lingering

By default, user services stop when the user logs out. Lingering keeps them running even without an active session:

# Run this as root (or with sudo)
sudo loginctl enable-linger openclaw

Think of lingering like telling the system: “Even if nobody is logged in as openclaw, keep their background services running.”

Install the Gateway Service

Critical: You must SSH directly as the openclaw user for the next step. Do not use su - openclaw from root.

ssh openclaw@YOUR_SERVER_IP
openclaw gateway install
openclaw gateway start
openclaw gateway status

You should see Runtime: running.

Why does direct SSH matter?

This trips up many people. Here’s what’s actually happening:

When you run su - openclaw from root, Linux switches your shell to the openclaw user, but it doesn’t go through the full login process. Systemd user services depend on something called a PAM session — a handshake that happens during a real login. Direct SSH triggers PAM. su - does not.

Without a PAM session, the systemd user daemon never starts, and commands like systemctl --user fail with cryptic errors like Failed to connect to bus: No such file or directory.

Always use direct SSH when working with systemd user services.


6. Install External CLI Dependencies

Some OpenClaw skills require external command-line tools that aren’t available via npm. We’ll install them using Homebrew — a package manager originally from macOS that also runs on Linux.

Install Homebrew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

This downloads and runs the official Homebrew installer. After it finishes, add Homebrew to your PATH:

echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv bash)"' >> ~/.bashrc
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv bash)"
brew --version

You should see something like Homebrew 5.0.14.

Install Build Tools

Some Homebrew packages need to be compiled from source code, which requires a C compiler. You need two separate compilers because they serve different lookup paths:

sudo apt-get install -y build-essential
brew install gcc

Installing both ensures that any formula can find a compiler regardless of where it looks.

Install Skill Binaries

# gog: Google Workspace CLI (for Gmail, Calendar, Drive)
brew install steipete/tap/gogcli

# himalaya: CLI email client for IMAP/SMTP
brew install himalaya

Now reinstall the skills that failed during onboarding:

openclaw configure --section skills
# Select: github, gog, obsidian

They should install successfully this time.


7. Configure Gmail (Himalaya)

Himalaya is a command-line email client. OpenClaw uses it to read and send emails on your behalf.

Gmail Prerequisites

Before configuring Himalaya, set up your Gmail account to allow it:

  1. Enable IMAP: Gmail → Settings (gear icon) → See all settings → Forwarding and POP/IMAP → Enable IMAP
  2. Enable 2-Step Verification: myaccount.google.com → Security → 2-Step Verification
  3. Create an App Password: myaccount.google.com → Security → App passwords → Create a new one (name it “OpenClaw” or whatever you want)

Why an App Password?

Gmail doesn’t allow third-party apps to log in with your regular password, that would be a major security risk (any tool that knows your password could access everything in your account). Instead, Google generates a 16-character App Password specifically for one application. It only works for that app, has limited scope, and can be revoked at any time without changing your main account password. Copy it when it appears, Google won’t show it again.

Create the Config File

Use a heredoc (<< 'EOF') to write the config. Don’t use a text editor like nano for this — editors often silently convert straight quotes (") to “smart quotes” (""), which causes config parse errors that are very hard to debug.

mkdir -p ~/.config/himalaya
cat > ~/.config/himalaya/config.toml << 'EOF'
[accounts.openclaw]
email = "your_email@gmail.com"
display-name = "OpenClaw Assistant"
default = true

backend.type = "imap"
backend.host = "imap.gmail.com"
backend.port = 993
backend.encryption.type = "tls"
backend.login = "your_email@gmail.com"
backend.auth.type = "password"
backend.auth.raw = "YOUR-16-CHAR-APP-PASSWORD"

message.send.backend.type = "smtp"
message.send.backend.host = "smtp.gmail.com"
message.send.backend.port = 587
message.send.backend.encryption.type = "start-tls"
message.send.backend.login = "your_email@gmail.com"
message.send.backend.auth.type = "password"
message.send.backend.auth.raw = "YOUR-16-CHAR-APP-PASSWORD"
EOF

Replace your_email@gmail.com and YOUR-16-CHAR-APP-PASSWORD with your actual values.

Why two separate sections (IMAP and SMTP)?

These are two completely different protocols:

Think of them as two separate doors to the same post office: one for picking up mail, one for dropping it off.

Test Your Setup

himalaya envelope list

You should see a list of recent emails from your inbox. If you get an authentication error, double-check your App Password.


8. Configure GitHub

Create a Personal Access Token (PAT)

  1. Go to: github.com/settings/tokens?type=beta
  2. Click Generate new token
  3. Set the following permissions:
    • Contents: Read and write
    • Pull Requests: Read and write
    • Metadata: Read-only (required by GitHub for any token)

What do these permissions mean?

Copy the generated token. You won’t be able to see it again.

Add the Token to OpenClaw

echo 'GITHUB_TOKEN=github_pat_xxx' >> ~/.openclaw/.env

Replace github_pat_xxx with your actual token.

Authenticate the GitHub CLI

echo $GITHUB_TOKEN | gh auth login --with-token
gh auth setup-git
gh auth status

9. Set Up a Project Workspace

Here’s an example of setting up a Next.js project that OpenClaw will manage.

Create the Project

cd ~
npx create-next-app@latest my-project --typescript --tailwind --eslint --app --src-dir --no-import-alias

Push to GitHub

cd ~/my-project
git remote add origin YOUR_REPO_URL
git branch -M main
git push -u origin main

Write Explicit Workspace Instructions

Create a markdown file that OpenClaw reads before every interaction:

mkdir -p ~/.openclaw/workspace
nano ~/.openclaw/workspace/my-project.md

This is the most important step for reliable automation. LLM agents stop early if instructions are vague. The difference between instructions that work and instructions that don’t is specificity.

Vague (will fail):

Create a feature branch, write the code, and open a PR.

Explicit (will work):

When asked to make a change to the project:

Step 1: Run git checkout -b feature/BRANCH-NAME using a descriptive branch name. Step 2: Make the requested code changes. Step 3: Run git add -A && git commit -m 'feat: describe what changed'. Step 4: Run git push origin feature/BRANCH-NAME. Step 5: Run gh pr create --title 'feat: describe what changed' --body 'Short description'. Step 6: Send the PR URL to the user via WhatsApp.

Do not stop until all 6 steps are complete. Do not ask for confirmation between steps.

The instructions need to be explicit because the agent reads them fresh each time, has no memory of previous sessions, and will genuinely stop at “open a PR” if it doesn’t know exactly what that means in terms of shell commands.


10. Run a Security Check

openclaw doctor

This checks that permissions on your config directory are tight (should be 700, meaning only the openclaw user can read or write it) and that no sensitive files are exposed. Fix any warnings it reports before going further.


Troubleshooting

ProblemFixWhy it works
EACCES during npm install -gSet a custom npm prefix (npm config set prefix '~/.npm-global')npm defaults to a root-owned directory; the prefix moves installs to your home folder where you have write access
Gateway stops after SSH logoutRun sudo loginctl enable-linger openclawUser services are tied to active login sessions by default; lingering keeps them alive
systemctl --user fails with “no such file”SSH directly as the user, don’t use su -su - skips the PAM login handshake that starts the systemd user daemon
Homebrew formula fails to buildInstall build-essential via apt AND brew install gccSome formulas look for a compiler at system paths; others require Homebrew’s own GCC
Himalaya config parse errorUse heredoc (cat > file << 'EOF') instead of nanoText editors convert straight quotes to smart quotes, which break TOML parsing
git push fails with authentication errorRun gh auth setup-gitgit and gh use separate credential systems; this command connects them
OpenClaw stops mid-workflowMake workspace instructions more explicit, with numbered steps and a “do not stop” directiveLLM agents follow instructions literally; if the instructions are vague, the agent stops when it thinks it’s done
.bashrc error on loginRemove stale entries with sed -i '/pattern/d' ~/.bashrcA previous install may have added completion scripts that no longer exist

Optional: Reset a Broken Installation

Only follow this section if you installed OpenClaw under the wrong user (e.g., root), have a broken WhatsApp pairing, or want to start completely fresh.

As the user with the broken install:

openclaw uninstall
# Select: Gateway service, State + config, Workspace
npm uninstall -g openclaw
rm -rf ~/.openclaw

Remove any stale entries the old install added to your shell config:

sed -i '/openclaw/d' ~/.bashrc
source ~/.bashrc

What sed -i '/openclaw/d' ~/.bashrc does:

After this, return to Step 1 and follow the guide from the beginning.


Final State

After completing all steps, you have:

This is not a toy setup. From here, OpenClaw becomes something you can message on WhatsApp and watch take real actions on your behalf.