How to Set Up OpenClaw on a VPS (The Right Way)
So you've heard about OpenClaw. You want your own AI assistant running on your server, texting you back on Telegram, reading your emails, managing files — the whole thing. That sounds great, and it works exactly like that.
But here's the thing nobody mentions upfront: a scan of OpenClaw instances running on common VPS providers shows a lot of them sitting wide open on the internet with zero authentication. API keys, email access, shell commands — all exposed to anyone who knows where to look.
This guide sets it up properly. From a completely fresh Ubuntu VPS to a hardened, private AI assistant that only responds to you. Don't skip the security steps. They're not optional.
What You Actually Need Before Starting
- A fresh Ubuntu VPS
- SSH access to that server
- Node.js 24 (Node 22.16+ also works — we'll install this)
- An API key from Anthropic, OpenAI, or Google
- A Telegram account (we'll set up the bot channel at the end)
That's it. Let's go.
Step 1 — Lock Down SSH First
Before anything else, SSH needs to be hardened. Password logins and root access are the two biggest entry points for attackers.
sudo nano /etc/ssh/sshd_config
Find these lines and set them explicitly:
PasswordAuthentication no
PermitRootLogin no
Save and reload:
sudo sshd -t && sudo systemctl reload ssh
Make sure your SSH key is already added before doing this. If you lock yourself out here, you'll need VPS console recovery access.
Step 2 — Set Up a Default-Deny Firewall
Block everything incoming by default, then only open what you need:
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
Step 3 — Install fail2ban
This auto-bans IPs that hammer your server with failed login attempts. One command and it runs in the background:
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
Step 4 — Install Tailscale
This is the part that changes everything. Tailscale creates a private mesh network between your devices. Once it's running, your server is only reachable from devices you control — not the open internet.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
Verify it connected:
tailscale status
You should see your server listed with a 100.x.x.x address. That's your private Tailscale IP.
Step 5 — Move SSH Behind Tailscale
Now that Tailscale works, stop exposing SSH to the public internet. Only allow SSH from your Tailscale network:
# Allow SSH only from Tailscale addresses
sudo ufw allow from 100.64.0.0/10 to any port 22 proto tcp
# Remove the public SSH rule
sudo ufw delete allow OpenSSH
From this point, you can only SSH in from a device that's on your Tailscale network. That's a massive reduction in attack surface.
Step 6 — Lock Web Ports Behind Tailscale Too
Same thing for HTTP and HTTPS. OpenClaw's gateway should only be reachable from your devices:
sudo ufw allow from 100.64.0.0/10 to any port 443 proto tcp
sudo ufw allow from 100.64.0.0/10 to any port 80 proto tcp
Step 7 — Install Node.js
OpenClaw requires Node 22+ and recommends Node 24. Ubuntu's default repositories ship an older version, so install from the official NodeSource:
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
Verify it installed correctly:
node --version
npm --version
If you see openclaw: command not found later even after installing, it's almost always a PATH issue. The fix:
npm prefix -g # shows where npm puts global binaries
Add that path to your shell startup file (~/.bashrc or ~/.zshrc):
export PATH="/path/from/npm/prefix/bin:$PATH"
Then open a new terminal or run source ~/.bashrc.
Step 8 — Install OpenClaw
curl -fsSL https://openclaw.ai/install.sh | bash
After install, run the onboarding wizard:
openclaw onboard --install-daemon
This walks you through picking a model provider, entering your API key, and configuring the gateway. Takes about 2 minutes.
Verify the gateway is running:
openclaw gateway status
You should see the gateway listening on port 18789. Then open the dashboard:
openclaw dashboard
If it loads in your browser, everything's working.
Step 9 — Lock the Bot to Owner-Only Access
By default, OpenClaw uses "pairing" for DM access — which is fine, but you can make it more locked-down by switching to an explicit allowlist. This way only your Telegram ID can ever message the bot, even if someone else somehow gets the bot's username.
In your OpenClaw config, add:
{
"channels": {
"telegram": {
"dmPolicy": "allowlist",
"allowFrom": ["YOUR_NUMERIC_TELEGRAM_ID"],
"groupPolicy": "allowlist"
}
}
}
To find your numeric Telegram ID, the cleanest way is to DM your bot first, then check the logs:
openclaw logs --follow
Read the from.id value from the log output. That's your numeric ID.
Never add OpenClaw to group chats unless you've explicitly configured which users in that group can issue commands. Every person in an unfiltered group can send commands to your server through the bot.
Step 10 — Enable Sandbox Mode
OpenClaw can run risky operations inside a container instead of directly on your system. If the agent does something unexpected, the blast radius is contained to the sandbox, not your actual server.
Check the security docs and enable isolation in your config. This is worth the few minutes it takes to set up.
Step 11 — Whitelist Allowed Commands
Don't let the agent run arbitrary shell commands. Explicitly list only what it actually needs:
{
"allowedCommands": ["git", "npm", "curl"],
"blockedCommands": ["rm -rf", "sudo", "chmod"]
}
Here's why this matters: prompt injection attacks are real with AI assistants that have shell access. If someone sends a malicious email to an account OpenClaw can read, that email could contain hidden instructions that the agent follows. With a command whitelist in place, even a successful prompt injection can only run commands from that list.
This actually happened to someone in the OpenClaw community. They received an email with hidden instructions embedded in it. OpenClaw followed them and deleted all emails — including the trash folder. Not theoretical. It happened.
Step 12 — Use Scoped API Tokens
When you connect services like GitHub, Gmail, or Google Drive, don't use full-access tokens. Get the minimum permissions needed:
- Read-only where possible
- Scoped to specific resources, not your entire account
- Never reuse tokens across different services
If something goes wrong, damage is limited to what that specific token can do.
Step 13 — Fix Credential File Permissions
Don't leave secrets world-readable:
chmod 700 ~/.openclaw/credentials
chmod 600 .env
Step 14 — Run the Security Audit
openclaw doctor
This catches issues you missed. If the audit flags something, fix it before you start using the bot. Don't skip this.
Verify Everything Is Locked Down
Run all four checks:
sudo ufw status
ss -tulnp
tailscale status
openclaw gateway status
What you want to see:
- No public SSH
- No public web ports
- Server only reachable via Tailscale
- Gateway running and healthy
Setting Up the Telegram Bot
- Open Telegram, search for @BotFather (verify it's the real one — blue checkmark)
- Send
/newbotand follow the prompts - Copy the bot token it gives you
- Configure it in your OpenClaw config:
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "YOUR_BOT_TOKEN_HERE",
"dmPolicy": "pairing"
}
}
}
- Start the gateway:
openclaw gateway
Approving Your First Pairing
After setup, message your bot on Telegram. It won't respond yet — you need to approve the pairing:
openclaw pairing list telegram
openclaw pairing approve telegram YOUR_CODE
Pairing codes expire after 1 hour, so approve it promptly. After that, message the bot again and it should respond.
Common Errors and What They Mean
"no auth configured" — Re-run openclaw onboard and set up authentication again.
Bot not responding — You probably forgot to approve the pairing. Run openclaw pairing list telegram then approve the code.
"node: command not found" — Node.js isn't installed properly or isn't on your PATH. Run the NodeSource install command from Step 7.
Gateway won't start — Run openclaw doctor and read what it flags. Fix those before trying again.
"refusing to bind gateway without auth" — You're trying to bind to a non-loopback address without setting a gateway token or password. Add gateway.auth.token to your config.
A Word on Model Choice
If you want the strongest resistance to prompt injection attacks, Claude Opus has been specifically trained to resist them — Anthropic's internal testing shows around 99% resistance. That's one layer of protection. The command whitelisting, sandboxing, and scoped API tokens are the others. Use all of them.
Quick Reference: Key Commands
# Check gateway status
openclaw gateway status
# Restart the gateway
openclaw gateway restart
# Watch live logs
openclaw logs --follow
# Run health check
openclaw doctor
# Check channel connections
openclaw channels status --probe
# List pending pairings
openclaw pairing list telegram
# Approve a pairing
openclaw pairing approve telegram <CODE>
That's the full setup. A private AI assistant that lives on your server, responds only to you, and isn't sitting open on the internet waiting to get compromised. The security steps take an extra 15 minutes — they're worth it.
If you run into issues not covered here, the OpenClaw Discord at has an active community and the official docs cover every config option in detail.
