How to self-host OpenClaw on a VPS
OpenClaw is an MIT-licensed AI assistant platform that connects to 23+ messaging channels — WhatsApp, Telegram, Slack, Discord, and more. Running it on your own VPS means your data stays on your hardware, you pick the LLM provider, and you pay only for compute. This guide covers installation, BYOK configuration, channel setup, and production HTTPS with Caddy.
Updated 1 October 2026: Node 24 and a pinned version
On 29 September 2026 a fresh npm install -g openclaw@latest stopped producing a working agent, with nothing changed on our side. latest had become 2026.9.6, which needs Node >=24.16 <25 || >=26.1; on the Node 22 this guide used to install, the service exits with node:sqlite truncates TEXT at embedded NUL ... use 24.16+/26.1+ and restarts in a loop. The steps below now install Node 24 and pin 2026.9.6, the version our weekly canary passed on 30 September 2026. Why we stopped trusting latest at all: pin your agent versions.
Requirements
- Ubuntu 22.04+ / Debian 12 / macOS / Windows WSL2
- Node.js 24.16+ (or 26.1+). OpenClaw 2026.9.6 declares
>=24.16 <25 || >=26.1; Node 22 no longer runs it - A VPS with at least 1 GB RAM and a public IP address
- An API key for Claude 4, GPT-4o, Gemini, or DeepSeek (BYOK)
- A domain or subdomain pointing at your VPS (for HTTPS)
Step 1 — Install Node.js 24
# Install Node.js 24 via NodeSource
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version # must print v24.16.0 or later (or v26.1+)If you use the official nodejs.org tarball instead of NodeSource’s package, run sudo apt install -y libatomic1 first on Ubuntu 22.04: that build links libatomic.so.1, which DigitalOcean’s 22.04 image does not ship. Our own installs use a private, checksum-verified Node v24.21.0 so the agent’s runtime cannot be changed by anything else on the box.
Step 2 — Install OpenClaw
Install the global npm package at an exact version, then run the built-in daemon installer:
# An exact version, not @latest: 2026.9.6 is what we validated (2026-09-30)
npm install -g openclaw@2026.9.6
openclaw --version
openclaw onboard --install-daemonThe --install-daemon flag writes a systemd unit so OpenClaw starts on boot automatically. You can still run it manually with openclaw start.
Step 3 — Add your BYOK API key
OpenClaw supports multiple providers. Set the key for the model you want to use:
openclaw config set llm.provider anthropic
openclaw config set llm.apiKey sk-ant-...
openclaw config set llm.model claude-opus-5Step 4 — Connect messaging channels
OpenClaw supports 23+ channels. Here are the two most common:
Telegram
# 1. Create a bot with @BotFather in Telegram — copy the token
# 2. Register it with OpenClaw:
openclaw channels add telegram --token 123456789:ABCdef...WhatsApp (via Meta Business API)
# Follow Meta's Business API setup to get your token and phone number ID
openclaw channels add whatsapp \
--token EAAG... \
--phone-number-id 123456789012345Run openclaw channels list to see all supported integrations including Slack, Discord, Signal, and SMS.
Step 5 — HTTPS with Caddy
Caddy automatically provisions and renews TLS certificates via Let's Encrypt. Install it and create a simple Caddyfile:
sudo apt install -y curl
curl -fsSLo caddy.deb "https://github.com/caddyserver/caddy/releases/download/v2.11.7/caddy_2.11.7_linux_$(dpkg --print-architecture).deb"
sudo apt install -y ./caddy.debReplace agent.yourdomain.com with your actual subdomain and ensure port 80/443 are open in your firewall. OpenClaw defaults to port 3000.
Step 6 — Verify and maintain
# Check status
openclaw status
# View logs
journalctl -u openclaw -f
# Update deliberately: name the version you tested on a throwaway box
npm install -g openclaw@<tested-version>
sudo systemctl restart openclawDo not update with @latest on the machine you depend on. A new release can raise its runtime requirement without warning, which is exactly how 2026.9.6 broke installs on Node 22. Check the release’s engines field, try it on a disposable server, then move the pin.
“Running” is not the same as “working”
openclaw status tells you the process is alive. It does not tell you the agent can reach your LLM provider — those are separate failures, and the second one is invisible until someone actually asks it something. We provision this stack repeatedly for testing, and we have had installs finish completely clean, the service report healthy, and the agent still be unable to answer a single prompt because the provider rejected the key.
So finish by sending one real message through a channel you connected in Step 4, with journalctl -u openclaw -f open in another terminal. A reply is the only proof that the install, the key, the model name and the provider account are all correct at once.
Troubleshooting — what actually goes wrong
We install this stack on fresh, disposable VPS instances continuously to test our own provisioning. Almost none of the failures we see are the install itself — they cluster at the boundary between the agent and the model provider, which is the part no install script can verify for you.
The agent installs fine and answers nothing
By far the most common outcome. The install script exits 0, the service is running, and every prompt fails, because the model provider is rejecting the request. Provider errors surface in the agent's log rather than at install time, and they are usually about the account rather than the code — an exhausted credit balance, a spend cap, a key scoped to the wrong model. A real example, taken verbatim from one of our runs where an OpenRouter key had hit its cap:
HTTP 502 {"error":{"message":"Upstream provider error","type":"upstream_error",
"details":{"error":{"message":"Key limit exceeded (total limit). Manage it using
https://openrouter.ai/workspaces/default/keys/..."}}}}Nothing was wrong with the machine, the install or the config. The fix was a billing page. Before debugging the agent, confirm the key works on its own — test it directly against the provider, outside OpenClaw entirely:
# Anthropic — a minimal request that costs almost nothing
curl -s 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-opus-5","max_tokens":16,
"messages":[{"role":"user","content":"say ready"}]}'
# OpenAI-compatible providers (OpenAI, OpenRouter, a gateway):
curl -s https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "content-type: application/json" \
-d '{"model":"gpt-4o","max_tokens":16,
"messages":[{"role":"user","content":"say ready"}]}'If that curl fails, no amount of OpenClaw configuration will help. If it succeeds and the agent still cannot answer, the problem is the key, model name or base URL as OpenClaw has them — not the provider.
Restart loop after an install or update: the wrong Node
Verbatim from our 29 September 2026 failure, when latest moved to 2026.9.6 on a server with Node 22:
node:sqlite truncates TEXT at embedded NUL ... use 24.16+/26.1+The process exits 1 and systemd restarts it forever. node --version tells you whether this is your problem; Step 1 is the fix. Our installer now also refuses to report success unless the service stays up for 20 seconds and port 18789 answers, because a unit that starts and dies a second later looks healthy to a quick check.
Memory search fails with 401
OpenClaw’s memory search embeds with OpenAI by default: it calls api.openai.com with whatever is in OPENAI_API_KEY. If that variable holds a key for a different OpenAI-compatible endpoint (a gateway, OpenRouter), every index and search is a 401 from OpenAI while chat works fine. We found this on 29 September 2026. Point memory search at your own endpoint (keys checked against the 2026.9.6 package):
// ~/.openclaw/openclaw.json (excerpt)
"memory": {
"search": {
"provider": "openai",
"model": "openai/text-embedding-3-small",
"remote": {
"baseUrl": "https://your-openai-compatible-endpoint/v1",
"apiKey": "sk-..."
}
}
}Use the embedding model id your endpoint lists. Then check it with openclaw memory index --force and a openclaw memory search for something you know is in your files. On our test server (run 20260929-215021) that indexed 2 files, returned the right line at a score of 0.607, made zero calls to api.openai.com, and cost 48 tokens in total: about $0.000001. Embeddings are not the cost to worry about; where the request goes is.
Every message costs about the same, however short
We measured about 24,500 input tokens for a single openclaw agent --message turn on 2026.9.2 (19 September 2026). Almost all of that is OpenClaw’s own system prompt and tool definitions, so a “hello” costs nearly as much as a real task: about $0.07 a turn at a $3-per-million-token list price, before caching. The breakdown, and how it compares with Hermes, is in what an AI agent turn costs.
The web UI does not load right after setup
Caddy terminates TLS and proxies to OpenClaw on its local port, so a failure here is usually one of two things, and they look identical from a browser. Either DNS is not resolving to this server yet, or Caddy is up and the agent behind it is not:
dig +short openclaw.yourdomain.com # must be THIS server's IP
sudo ss -ltnp | grep -E ':80|:443|:18789'
journalctl -u caddy -n 30 --no-pager
curl -I http://127.0.0.1:18789 # does the agent answer locally at all?Point DNS before the first request. Certificate issuance itself is fast — in our provisioning runs Caddy obtained one for a brand-new subdomain in about seven seconds — but querying the hostname too early has a long tail: Cloudflare-hosted zones publish a 30-minute negative-cache TTL, so a “does not exist” answer can outlive the record going live by half an hour. If you hit that, sudo resolvectl flush-caches or wait.
Do not publish the agent's port
OpenClaw should listen on loopback and be reached through Caddy. If you ever run a piece of this stack in Docker, be aware that Docker writes iptables rules evaluated before UFW's: a published container port is reachable from the internet even when ufw status says that port is denied. We measured a database container going from unreachable to publicly open the moment it started, with no firewall rule changed. Bind to 127.0.0.1 and let the proxy be the only thing listening — see our VPS security guide for the full detail.
Prefer not to manage it yourself?
AgentOcean manages OpenClaw on a dedicated VPS — HTTPS, monitoring, and one-click updates — without you touching a terminal.