By the end of this guide, your OpenClaw instance will:
- Run 24/7 on a VPS, surviving SSH logout
- Be connected to WhatsApp
- Use OpenRouter as the LLM provider
- Support Brave Search for web lookups
- Have Gmail access via IMAP/SMTP
- Authenticate with GitHub for repository management
- Auto-restart via systemd if it ever crashes
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:
- AWS
- Contabo
- …
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:
adduser openclaw— creates a new user namedopenclawwith a home directory at/home/openclaw/usermod -aG sudo openclaw— adds the user to thesudogroup, which allows it to run admin commands when needed (prefixed withsudo)
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:
mkdir -p ~/.npm-global: creates a folder in your home directory to hold global packages (~is shorthand for your home directory;-pmeans “create parent directories if they don’t exist”)npm config set prefix '~/.npm-global': tells npm to use that folder as its global install locationecho '...' >> ~/.bashrc: appends a line to your shell config so the new folder is included in your PATH (where the system looks for commands). The>>means “append” — don’t use>which would overwrite the filesource ~/.bashrc: reloads the config immediately so you don’t have to log out and back in
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:
| Prompt | Selection |
|---|---|
| Onboarding mode | QuickStart |
| Channel | |
| Phone setup | Personal phone number |
| WhatsApp number | Your number (e.g. +52XXXXXXXX) |
| Configure skills | Yes |
| Skills to install | clawhub, github, gog, mcporter, obsidian |
| Node manager | npm |
| Hooks | session-memory |
| DM policy | allowlist |
Scan the WhatsApp QR Code
During onboarding, a QR code will appear in your terminal. On your phone:
- Open WhatsApp → Settings → Linked Devices → Link a Device
- 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
githubandgog) 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:
- Select: Local (this machine)
- Model: openrouter/auto
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.
4. Configure Web Search
Enable Brave Search so OpenClaw can look things up on the web:
openclaw configure --section web
- Enable
web_fetch: Yes - Enter your Brave Search API key when prompted
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:
- System units: run as root, manage things like web servers and databases
- User units: run as a specific user, scoped to their account
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
build-essential: (apt) installsgccat standard system paths like/usr/bin/gcc. Many Homebrew formulas look for a compiler here during their build process.brew install gcc: installs a Homebrew-managed GCC (e.g.gcc-15). Some formulas specifically require Homebrew’s own compiler, not the system one.
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:
- Enable IMAP: Gmail → Settings (gear icon) → See all settings → Forwarding and POP/IMAP → Enable IMAP
- Enable 2-Step Verification: myaccount.google.com → Security → 2-Step Verification
- 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:
- IMAP (port 993) is for reading email — it syncs your inbox from Gmail’s servers to your local client
- SMTP (port 587) is for sending email — it relays your outgoing messages through Gmail’s mail servers
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)
- Go to: github.com/settings/tokens?type=beta
- Click Generate new token
- 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?
- Contents gives the token the ability to read files from and write (push) files to your repositories. Without it,
git pushwill fail. - Pull Requests lets the token open, comment on, and manage PRs. This is what allows OpenClaw to create a PR after pushing a branch.
- Metadata is read-only access to basic repository information (name, description, visibility). GitHub requires it as a baseline for any token — you can’t opt out.
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
gh auth login --with-token: logs theghCLI into your GitHub account using the token you just addedgh auth setup-git: wires regulargitcommands to useghas a credential helper. Without this,git pushwill ask for a username and password separately, and may fail. This step connects the two systems so they share authenticationgh auth status: confirms you’re logged in. You should see your username (e.g.Logged in to github.com account your_username)
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
git remote add origin YOUR_REPO_URL: tells your local git repository where the remote copy lives (on GitHub)git branch -M main: renames the current branch tomain(GitHub’s default)git push -u origin main: pushes your code to GitHub; the-uflag setsorigin mainas the default so future pushes just needgit push
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-NAMEusing a descriptive branch name. Step 2: Make the requested code changes. Step 3: Rungit add -A && git commit -m 'feat: describe what changed'. Step 4: Rungit push origin feature/BRANCH-NAME. Step 5: Rungh 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
| Problem | Fix | Why it works |
|---|---|---|
EACCES during npm install -g | Set 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 logout | Run sudo loginctl enable-linger openclaw | User 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 build | Install build-essential via apt AND brew install gcc | Some formulas look for a compiler at system paths; others require Homebrew’s own GCC |
| Himalaya config parse error | Use heredoc (cat > file << 'EOF') instead of nano | Text editors convert straight quotes to smart quotes, which break TOML parsing |
git push fails with authentication error | Run gh auth setup-git | git and gh use separate credential systems; this command connects them |
| OpenClaw stops mid-workflow | Make workspace instructions more explicit, with numbered steps and a “do not stop” directive | LLM agents follow instructions literally; if the instructions are vague, the agent stops when it thinks it’s done |
.bashrc error on login | Remove stale entries with sed -i '/pattern/d' ~/.bashrc | A 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:
sed— a stream editor for text files-i— edit the file in-place (rather than printing to screen)'/openclaw/d'— delete any line that contains the word “openclaw”~/.bashrc— the file to edit
After this, return to Step 1 and follow the guide from the beginning.
Final State
After completing all steps, you have:
- A persistent OpenClaw gateway running as a systemd user service
- WhatsApp channel connected and locked to your number
- OpenRouter powering the LLM
- Brave Search for real-time web lookups
- Gmail integration via Himalaya (IMAP + SMTP)
- GitHub CLI authenticated for branch, commit, and PR management
- Explicit workspace instructions for consistent automated workflows
- Auto-restart on crash, auto-start on reboot
This is not a toy setup. From here, OpenClaw becomes something you can message on WhatsApp and watch take real actions on your behalf.