To run OpenClaw on a VPS safely, install it as a normal Linux user without sudo rights, keep its gateway on 127.0.0.1 port 18789 behind a long token, reach the dashboard through an SSH tunnel or Tailscale, and change the tool settings before you connect a chat app. That last step matters most. In our lab, the onboarding wizard of OpenClaw 2026.10.2 left the agent on the "full" tool profile, and when the model asked to run a shell command, it ran directly on the server without asking anyone. Plan on at least 4 GB of RAM: the gateway alone used about 1 GB idle and 1.4 to 1.5 GB while busy.
Key facts, checked on 12 October 2026:
- OpenClaw 2026.10.2 is the current stable release, published on 12 October 2026 (GitHub releases). It is MIT-licensed and had 391,739 GitHub stars that day, read from GitHub's API.
- It needs Node 24.16 or newer, or 26.1+ (install docs). In our lab it listened on port 18789 and kept its state in
~/.openclaw. - The project published 722 security advisories on GitHub between 31 January and 11 September 2026: 14 critical, 249 high, 390 medium and 69 low (advisory list). GitHub lists six non-beta releases published between 2 and 12 October.
- SecurityScorecard found 40,214 OpenClaw instances exposed to the internet on 28,663 IP addresses and rated 63% of observed deployments vulnerable (Infosecurity Magazine, 9 February 2026).
- In our lab (Debian 13, 2 vCPU, 4 GB RAM) the install took 58 seconds and the gateway peaked at 1,378 MB during six parallel chats. With a 2 GB limit, the first sandboxed command got the gateway killed for lack of memory.
What OpenClaw does, in plain words
OpenClaw is a personal AI assistant you host yourself. One long-running program, the gateway, connects your chat apps (WhatsApp, Telegram, Discord, Slack, Signal, iMessage, Microsoft Teams and about 20 more) to an AI model you pick. Our install offered almost 100 sign-in options, from Anthropic, OpenAI and Google to OpenRouter and local models through Ollama or LM Studio. The gateway runs on your server and keeps memory, chat history and credentials there.
What makes it more than a chatbot is its tools: the model can read and write files, run shell commands, drive a browser and schedule jobs. Break into a normal web app and data leaks; break into an agent with a shell and commands run. Every setting below shrinks what a stranger, a bad link or a confused model can make it do.
What the defaults left open in our lab
We installed 2026.10.2 twice in Debian 13 containers, with the official rootless installer and with the official Docker image. The native gateway listened only on 127.0.0.1 and ::1, required a token, and kept ~/.openclaw at mode 700. Four other defaults need your attention:
- Onboarding wrote
tools.profile: "full". The model was offered 12 tools directly, includingexec,writeandapply_patch. OpenClaw's exec documentation says it plainly: "No-approval host exec is the default for gateway and node". - The official
docker-compose.ymlpublishes ports 18789, 18790 and 3978 on every network interface, and Docker's port rules skip the host firewall. Inside our Docker test, the security audit still reported the gateway as loopback-only. It reads the config file, while the stock compose file starts the gateway with--bind lan. - The audit listed elevated exec (the escape hatch out of a sandbox) and browser control as enabled.
- A provider key given during onboarding was stored in plain text inside
openclaw.json.
Binding to 127.0.0.1 is necessary but not enough. Advisory GHSA-g8p2-7wf7-98mq (31 January 2026, CVSS 8.8) let a crafted link steal the gateway token through the owner's own browser, even on a loopback-only gateway. CVE-2026-25593 (4 February 2026, CVSS 8.4) let any local process without a token rewrite the config and run commands. Current releases fix both, but only servers that update get the fix, so updates are part of the security setup.
The security checklist
The whole guide on one screen. The sections below show how we tested each row.
| Check | Why it matters | How we verified it |
|---|---|---|
| Gateway on 127.0.0.1 only | The dashboard controls everything the agent can do | ss -ltn showed only 127.0.0.1 and [::1]; outside connections timed out |
| Token of 64 hex characters | Local programs are attackers too (CVE-2026-25593) | Kept in ~/.openclaw/.env, mode 600 |
| Firewall: deny incoming, allow SSH | Catches services you start later and forget | ufw status verbose |
| Docker ports published on 127.0.0.1 | Published container ports bypass UFW | docker compose config showed host_ip: 127.0.0.1 |
| Own user, no sudo | A hijacked agent gets that user's rights and nothing more | id claw lists no sudo group |
| Tool profile other than "full" | The default lets the model run shell commands without approval | Tools offered to the model fell from 12 to 4 |
| Shell commands only in a sandbox | A throwaway container with no network limits the damage | The test command printed uid=1000(sandbox) and NO-NETWORK |
| Elevated exec off | It is the way out of the sandbox | Audit: tools.elevated: disabled |
| API keys as references, not plain text | Config files end up in backups, tickets and screenshots | grep found 0 copies of the key in openclaw.json |
| DM pairing and mention-only groups | Strangers can't talk to your agent | From the docs; needs a real chat account, so not lab-tested |
| Weekly updates | 722 advisories in just over seven months | openclaw update status; a real update from 2026.10.1 |
| Verified, encrypted backups | Archives contain the token, keys and chat history | openclaw backup create --verify and a test restore |
| Audit after every change | Settings drift as you add channels and skills | openclaw security audit: 0 critical findings |
| One gateway per group of people who trust each other | Anyone who can message the agent can steer its tools | OpenClaw's trust model |
Layer 1: a user without sudo, and a closed firewall
On a fresh Debian 13 server, logged in as root, create a user called claw that owns OpenClaw and nothing else. "Linger" lets that user's background services start at boot without anyone logged in. The two install lines copy root's SSH key to claw, so they assume you log in with a key, not a password. For SSH hardening beyond this, see our Debian 13 security baseline.
# as root
apt update
apt install -y curl ca-certificates git ufw dbus-user-session
useradd -m -s /bin/bash claw
loginctl enable-linger claw
install -d -m 700 -o claw -g claw /home/claw/.ssh
install -m 600 -o claw -g claw /root/.ssh/authorized_keys /home/claw/.ssh/authorized_keys
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw --force enable
ufw status verbose
The last command should show Status: active and 22/tcp ALLOW IN for IPv4 and IPv6. Port 18789 is not opened, and it never will be.
Layer 2: install OpenClaw as that user
OpenClaw ships two Linux installers. install.sh installs Node system-wide from NodeSource's packages, which takes root. install-cli.sh downloads its own Node into ~/.openclaw and needs no root at all (installer docs). We used the second. Connect with ssh claw@YOUR_SERVER_IP:
# as the claw user
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash
echo 'export PATH="$HOME/.openclaw/bin:$PATH"' >> ~/.profile
exit
It printed OpenClaw installed (OpenClaw 2026.10.2 (b8952d4)) after 58 seconds and used 820 MB of disk, including its own Node 24.21.0. Log in again so the new PATH applies. Now create the gateway token in a file only claw can read, and run the setup wizard without questions:
# as the claw user, after logging in again
openclaw --version
umask 077
printf 'OPENCLAW_GATEWAY_TOKEN=%s\n' "$(openssl rand -hex 32)" > ~/.openclaw/.env
set -a; . ~/.openclaw/.env; set +a
openclaw onboard --non-interactive --accept-risk --mode local \
--auth-choice skip --gateway-bind loopback --gateway-auth token \
--gateway-token-ref-env OPENCLAW_GATEWAY_TOKEN \
--skip-channels --skip-search --skip-skills --install-daemon
The config now refers to the token by its variable name instead of containing it, and --install-daemon creates a systemd user service that brings the gateway back if it crashes (we saw that happen in our memory test). On the first start the wizard may print "Gateway did not become reachable". Ours was still loading: the first start took about a minute, and the gateway answered 6 to 12 seconds after that message. Later restarts took 21 to 26 seconds. Check it:
# as the claw user
curl -fsS http://127.0.0.1:18789/healthz
ss -ltn | grep 18789
openclaw config validate
openclaw security audit
Expected: {"ok":true,"status":"live"}, two LISTEN lines on 127.0.0.1 and [::1] only, Config valid, and an audit with 0 critical findings. Its one warning, gateway.trusted_proxies_missing, only matters if you add a reverse proxy.
We skipped the model step because a lab can't sign in to a provider. For that step, OpenClaw's own doctor check points to openclaw configure --section model, which we did not test. To keep the API key out of the config, put it in ~/.openclaw/.env and reference it with openclaw config set <path> --ref-provider default --ref-source env --ref-id <VARIABLE>. After we did that for a test key, grep found no copy of it in openclaw.json. Never pass keys as command-line flags: they land in your shell history.
Layer 3: reach the dashboard through a tunnel, not a port
An SSH tunnel carries the dashboard over your SSH login. Run this on your own computer and leave it open:
# on your own computer
ssh -N -L 18789:127.0.0.1:18789 claw@YOUR_SERVER_IP
On the server, openclaw dashboard --json prints a browserUrl with a one-time pairing code that works for ten minutes. Open it in your browser while the tunnel runs. Through the same kind of tunnel in our lab, /healthz answered and the page title read "OpenClaw Control", while a direct connection to port 18789 from outside timed out.
From a phone, Tailscale is more comfortable. According to the Tailscale docs, gateway.tailscale.mode: "serve" keeps the gateway on 127.0.0.1 and serves it over HTTPS to your own tailnet devices only, while funnel publishes it to the internet. Our Tailscale VPS guide covers the install. If you need a public URL, use a reverse proxy with TLS, set gateway.trustedProxies and switch to password or trusted-proxy authentication, as the network exposure docs describe. Both paths need an account or a domain, so we did not lab-test them.
Layer 4: decide what the model's hands can do
To see what the model can do, we pointed OpenClaw at a small local stand-in that speaks the OpenAI API and always asks to run one command: id; hostname, a network check and a look for the Docker socket. With the onboarding defaults, it ran on the server as claw, reached the internet, and nobody was asked. Pick one of two fixes.
Option A: a chat assistant with no shell
This is OpenClaw's own hardened baseline, plus switching off local network discovery (mDNS):
# as the claw user
cat > ~/hardening.json5 <<'EOF'
{
session: { dmScope: "per-channel-peer" },
tools: {
profile: "messaging",
deny: ["group:automation", "group:runtime", "group:fs", "sessions_spawn", "sessions_send"],
fs: { workspaceOnly: true },
exec: { security: "deny", ask: "always" },
elevated: { enabled: false },
sessions: { visibility: "agent" },
agentToAgent: { enabled: false },
},
discovery: { mdns: { mode: "off" } },
}
EOF
openclaw config patch --file ~/hardening.json5
openclaw config validate
It applied without a restart. The tools offered to the model fell from 12 to 4 (sessions_yield, tool_call, tool_describe, tool_search), and the audit switched to tools.elevated: disabled.
Option B: shell commands, but only inside a container
If the agent should run code, let it do so in a Docker sandbox. The trade-off: membership of the docker group equals root on that server, so a compromised gateway could misuse it. OpenClaw also supports rootless Podman (backend: "podman"); we tested Docker only.
# as root
apt install -y docker.io
usermod -aG docker claw
systemctl restart user@$(id -u claw).service
Restarting claw's user services restarts the gateway too, so it picks up the new group (we checked in /proc). Then build the sandbox image from the sandboxing docs and turn the sandbox on:
# as the claw user
docker build -q -t openclaw-sandbox:bookworm-slim - <<'DOCKERFILE'
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bash ca-certificates curl git jq python3 ripgrep \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --shell /bin/bash sandbox
USER sandbox
WORKDIR /home/sandbox
CMD ["sleep", "infinity"]
DOCKERFILE
cat > ~/sandbox.json5 <<'EOF'
{
agents: {
defaults: {
sandbox: {
mode: "all",
backend: "docker",
scope: "session",
workspaceAccess: "rw",
docker: { network: "none", readOnlyRoot: true, capDrop: ["ALL"] },
},
},
},
tools: {
profile: "coding",
deny: ["group:automation", "sessions_spawn", "sessions_send"],
fs: null,
exec: { host: "sandbox", security: null, ask: null },
elevated: { enabled: false },
sessions: { visibility: "agent" },
agentToAgent: { enabled: false },
},
}
EOF
openclaw config patch --file ~/sandbox.json5
openclaw sandbox explain
The null values remove Option A's file and exec limits, in case you applied it first. The image built in 20 seconds (218 MB), and sandbox explain printed runtime: sandboxed. The same test command now printed uid=1000(sandbox), a container ID as hostname, Debian 12, NO-NETWORK and no Docker socket. An idle sandbox container used 652 KB of RAM; Docker itself added about 170 MB.
Keep the chat side strict too. According to OpenClaw's README, direct-message channels pair unknown senders by default, and you approve each one with openclaw pairing approve <channel> <code>. We could not test this without a chat account. Groups should require a mention, and WhatsApp or Signal deserve a separate phone number. If the agent needs your own data, a read-only MCP server is a narrower door than a shell.
Running it in Docker instead: publish on 127.0.0.1
The official image (ghcr.io/openclaw/openclaw, 3.3 GB) runs as the unprivileged node user with no-new-privileges and an unless-stopped restart policy. The catch is the port list. An override file fixes it, and Compose reads docker-compose.override.yml automatically:
# as root
apt install -y docker.io docker-compose git openssl
git clone -q --depth 1 --branch v2026.10.2 https://github.com/openclaw/openclaw.git /opt/openclaw
cd /opt/openclaw
install -d -o 1000 -g 1000 -m 700 /opt/openclaw-data /opt/openclaw-data/config /opt/openclaw-data/workspace /opt/openclaw-data/secrets
umask 077
cat > .env <<ENV
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw:2026.10.2
OPENCLAW_CONFIG_DIR=/opt/openclaw-data/config
OPENCLAW_WORKSPACE_DIR=/opt/openclaw-data/workspace
OPENCLAW_AUTH_PROFILE_SECRET_DIR=/opt/openclaw-data/secrets
OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
ENV
cat > docker-compose.override.yml <<'YAML'
services:
openclaw-gateway:
ports: !override
- "127.0.0.1:18789:18789"
YAML
docker compose pull -q openclaw-gateway
docker compose run -T --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js onboard --non-interactive --accept-risk --skip-health \
--mode local --auth-choice skip \
--gateway-auth token --gateway-token-ref-env OPENCLAW_GATEWAY_TOKEN \
--skip-channels --no-install-daemon
docker compose run -T --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set --batch-json '[{"path":"gateway.controlUi.allowedOrigins","value":["http://localhost:18789","http://127.0.0.1:18789"]}]'
docker compose up -d openclaw-gateway
docker compose config | grep -A6 '^ ports:'
The last command shows host_ip: 127.0.0.1 and only port 18789. From outside, our connection to 18789 was refused although this container had no firewall. The Docker install also started on the "full" tool profile. Save the Option A file as /root/hardening.json5 and, still in /opt/openclaw, apply it with docker compose exec -T openclaw-gateway node dist/index.js config patch --stdin < ~/hardening.json5. A sandbox inside Docker means mounting the Docker socket into the gateway, which hands it the host; for Option B, use the native install. Compose basics are in our Docker on a VPS guide.
Updates and backups
Back up first, then update. OpenClaw's backup command copies its SQLite databases safely while the gateway runs. Never copy the live .sqlite files by hand (backup docs).
# as the claw user
mkdir -p ~/backups && chmod 700 ~/backups
openclaw backup create --output ~/backups --verify
openclaw update status
openclaw update --dry-run
openclaw update --yes
Our first archive took 4.7 seconds and was 190 KB. It skips the reinstallable 820 MB Node folder but includes .env, so treat every archive as a secret. A real update from 2026.10.1 to 2026.10.2 took 11 minutes 20 seconds on two busy vCPUs, with 202 seconds of gateway downtime. The updater also left the previous runtime (about 600 MB) on disk until the next update or openclaw doctor --fix.
For a nightly backup that keeps 14 days, install cron as root (apt install -y cron) and add the job as claw:
# as the claw user
( crontab -l 2>/dev/null; echo '30 3 * * * $HOME/.openclaw/bin/openclaw backup create --output $HOME/backups --verify >> $HOME/backups/backup.log 2>&1; find $HOME/backups -name "*-openclaw-backup.tar.gz" -mtime +14 -delete' ) | crontab -
crontab -l
A backup on the same disk is not a backup. Copy ~/backups off the server with encryption; our restic offsite backup guide shows how. To test a restore, openclaw backup restore ARCHIVE --target ~/restore-test verifies the archive and unpacks it into an empty folder. Ours worked, and it warned that WhatsApp may need relinking after a rollback.
How big a server: our measurements
| Measurement (OpenClaw 2026.10.2, Debian 13, 2 vCPU) | Result |
|---|---|
| Gateway RAM, idle | About 1 GB (988 to 1,053 MB for the process and its workers) |
| Gateway RAM, six chats at once | 1,378 MB peak; eight at once peaked at 1.49 GB |
| Docker image instead, idle | 1.14 to 1.19 GiB (docker stats) |
| Twelve chats at once, 4 GB limit | Out of memory: the kernel killed the gateway and systemd restarted it 5 seconds later |
| 2 GB limit | 1.2 GB used idle, plain chats worked, the first sandboxed command ran out of memory |
| Disk | 820 MB program, 40 to 80 MB state, 218 MB sandbox image, 600 MB per retained update |
The twelve-chat test was harsh on purpose (each test client is its own Node process), but browsers, sandboxes and extra channels add up too. Our advice for RS Computers plans:
- VPS Nano (1 GB) and VPS Micro (2 GB) are too small for OpenClaw.
- VPS Mini (4 shared vCPU, 4 GB, 80 GB NVMe) suits one person with a chat assistant (Option A) or light sandbox use.
- VDS Small (4 dedicated vCPU, 8 GB, 240 GB NVMe) is the comfortable choice for Option B, browser tools and several channels. Dedicated vCPUs also suit CPU-heavy jobs like the 11-minute update we timed.
- VDS Medium (8 dedicated vCPU, 16 GB) fits separate gateways for separate people, or small local models (see our local LLM guide).
All plans run on KVM with NVMe, unmetered traffic and their own IPv4 and IPv6, and you can upgrade later from the client area with a short reboot. Servers are in Amsterdam, Dublin and Prishtina; availability by city is on the plans page. Comparing agents? See Hermes Agent on Telegram, Claude Code and Codex running 24/7 and a Claude Code trading bot on a VDS. Our bot hosting guide shows how to get a Telegram bot token from BotFather.
Frequently asked questions
Is OpenClaw safe to run on a VPS?
It can be, if you change the defaults. Keep the gateway on 127.0.0.1 with token authentication, run it as a user without sudo, replace the "full" tool profile with a restricted one or a Docker sandbox, and update often: the project published 722 security advisories between January and September 2026.
How much RAM does OpenClaw need?
Plan on 4 GB. In our lab, OpenClaw 2026.10.2 used about 1 GB idle and up to 1.4 GB with six parallel chats; with a 2 GB limit, the first sandboxed command ran out of memory. Use 8 GB for sandboxes, browser tools or several channels.
What port does OpenClaw use, and should I open it?
The gateway and its web dashboard use port 18789. Don't open it in the firewall. Reach it through an SSH tunnel with ssh -N -L 18789:127.0.0.1:18789 user@server, through Tailscale Serve, or behind a reverse proxy with authentication.
Can I run OpenClaw without Docker?
Yes. The rootless install-cli.sh installer puts Node and OpenClaw under ~/.openclaw and runs the gateway as a systemd user service. You only need Docker for the optional sandbox that runs the agent's shell commands.
Does OpenClaw need a GPU?
No. With a cloud provider such as Anthropic or OpenAI, the model runs at the provider and the server only runs the gateway. A GPU or much more RAM matters only for local models through Ollama or LM Studio.
How do I update OpenClaw safely?
Run openclaw backup create --output ~/backups --verify, then openclaw update --dry-run and openclaw update --yes as the user that owns the install. Expect downtime: in our lab, on two vCPUs of a busy test host, the update took 11 minutes 20 seconds and the gateway was down for 202 seconds.
Your assistant, on a server you control
OpenClaw is worth self-hosting when you set the limits: a user without sudo, a gateway nobody else can reach, a model that can't run commands outside a box, and backups you have restored once. Pick a VPS Mini or VDS Small on the plans page, or message us on Telegram if you want help choosing. If you would rather have us do the installation, we quote setup work per job on Telegram or by email.