TL;DR:
- To install OpenClaw on Ubuntu 24.04, install Node.js 24 LTS, create an unprivileged
openclawuser, run the official installer as that user, and install the gateway as a systemd user service. - Written against OpenClaw 2026.9.8 (released October 3, 2026), which needs Node 24.16+ or 26.1+.
- OpenClaw's docs list 1 GB RAM with swap as the minimum and 2 GB or more as recommended when the model runs through an API.
- The gateway uses port 18789 and binds to 127.0.0.1 by default. Keep 18789 closed in UFW and reach the dashboard through an SSH tunnel.
- OpenClaw's Compose file publishes port 18789 on every interface, and Docker's rules bypass UFW, so the Docker path needs
DOCKER-USERrules first.
OpenClaw, formerly Clawdbot and Moltbot, is an open-source (MIT) AI agent gateway that connects chat apps such as Telegram and Discord to a model provider and runs tools on its host. This tutorial shows how to install OpenClaw on an Ubuntu 24.04 VPS under a separate system user, keep the gateway on the loopback address behind the Uncomplicated Firewall (UFW), and connect Telegram. It also covers updates, backups and Docker. A VPS keeps the agent reachable while your laptop is off.
Applies to: Ubuntu 24.04 LTS · OpenClaw 2026.9.8 · Node.js 24.21 LTS · checked October 2026
Prerequisites
- A VPS running Ubuntu 24.04 LTS with at least 1 vCPU, 1 GB RAM (2 GB recommended) and root SSH access. Arct Cloud Linux images include root SSH and accept an SSH public key at deploy; see Linux VPS plans.
- A sudo user that logs in with an SSH key, called
deployhere. To create a key, see How to Generate an SSH Key. - An API key from a supported model provider, such as Anthropic or OpenAI.
- A Telegram account, if you want to message the agent from your phone.
If the server has only root, log in as root, create deploy, and copy your SSH key to it. adduser asks for the password that sudo uses:
adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy
Log out and reconnect with ssh deploy@YOUR_SERVER_IP. Commands run as deploy until Step 5. Replace values in capitals, such as YOUR_SERVER_IP, with your own.
How much RAM does OpenClaw need?
OpenClaw needs 1 GB RAM with swap at minimum and 2 GB or more when the model runs through an API, per its Raspberry Pi and DigitalOcean install pages.
| Setup | RAM | Source |
|---|---|---|
| Gateway with an API model | 1 GB plus 2 GB swap minimum; 2 GB or more recommended | OpenClaw install docs |
| Docker image built from source | 6 GB for the build; the pre-built image skips it | OpenClaw Docker docs |
Local models need RAM for the model on top; see best Ollama models for CPU servers. Sustained full-CPU load is not permitted on Arct Cloud plans, so keep local models to on-demand, interactive replies and send scheduled or batch work to an API model. For an API model, Cost Optimized cvm.nano (1 vCPU, 2 GB RAM, 25 GB NVMe) matches the recommended size, and cvm.pico (1 vCPU, 1 GB RAM, 15 GB NVMe) meets the minimum with the Step 2 swap file. Browser skills, Docker and extra agents add memory, so size up to 4 GB for those, such as cvm.micro (2 vCPU, 4 GB RAM, 40 GB NVMe).
Step 1: Update the server
Install updates, Git, UFW, the build tools the OpenClaw installer would add itself, and dbus-user-session for systemd user services.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git ufw build-essential python3 cmake dbus-user-session
If the upgrade installed a new kernel, reboot with sudo reboot and reconnect.
Step 2: Add a swap file
A swap file keeps a 1 GB or 2 GB server from killing processes when memory runs out. Check for existing swap with swapon --show, and skip this step if it lists a device. OpenClaw's 1 GB guide uses 2 GB of swap:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h now shows 2.0Gi in the Swap: row. Skip this step on 4 GB servers.
Step 3: Turn on the UFW firewall
UFW blocks every incoming connection you do not allow. Allow SSH before you enable it, or the session drops. Leave port 18789 closed.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
Type y to confirm. sudo ufw status now lists only OpenSSH (IPv4 and IPv6).
Step 4: Install Node.js 24 LTS
OpenClaw 2026.9.8 requires Node 24.16+ or 26.1+. Install Node 24 LTS from NodeSource, the line the OpenClaw installer uses on Linux:
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v
The output looks similar to this:
v24.21.0
OpenClaw's docs recommend Node 26, which starts the gateway faster and uses less memory than Node 24. To use it, replace setup_24.x with setup_26.x. A system-wide Node lets the OpenClaw installer run without sudo in Step 6.
Step 5: Create an unprivileged openclaw user
OpenClaw's agent can run shell commands, so run it as a separate system user without sudo rights. Lingering starts that user's services at boot.
sudo useradd --create-home --shell /bin/bash openclaw
sudo loginctl enable-linger openclaw
sudo -iu openclaw
You now have a shell as openclaw. A sudo -i shell does not set XDG_RUNTIME_DIR, which systemctl --user needs, so add it to the shell profile:
echo 'export XDG_RUNTIME_DIR="/run/user/$(id -u)"' >> ~/.bashrc
source ~/.bashrc
systemctl --user is-system-running
The last command prints running or degraded, so the user service manager answers. Steps 6 to 12 run as openclaw; return to this shell with sudo -iu openclaw.
Step 6: Run the OpenClaw installer
The official installer at https://openclaw.ai/install.sh checks Node and Git and installs the openclaw npm package. Preview it with a dry run, then install without onboarding:
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --dry-run
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard
The system npm prefix is not writable for openclaw, so the installer switches npm to ~/.npm-global and adds its bin directory to ~/.bashrc. Reload the shell and check the version:
source ~/.bashrc
openclaw --version
At the time of writing, the installer pulls OpenClaw 2026.9.8. Your output may show a newer version.
Step 7: Run OpenClaw onboarding
Onboarding saves the model provider, creates the agent workspace and generates a gateway token.
openclaw onboard
Choose Quick start, select your model provider, and paste the API key. OpenClaw tests the key with a real completion before saving it. On a server without a display, the wizard then runs the gateway in the foreground and prints a dashboard link. Press Ctrl+C to stop it; the configuration stays saved.
Quick start gives the default agent, main, full tool access. As openclaw, it can run commands and edit that user's files, but it cannot use sudo.
Step 8: Install the gateway as a systemd service
Install the gateway, the long-running OpenClaw process, as a systemd user service so it restarts after crashes and reboots:
openclaw gateway install
systemctl --user enable --now openclaw-gateway.service
openclaw gateway status
A healthy gateway reports Runtime: running and Connectivity probe: ok and listens on port 18789. Follow its logs with openclaw logs --follow.
Step 9: Open the dashboard through an SSH tunnel
The dashboard, called the Control UI, is an admin surface for chat, configuration and tool approvals, so it stays on 127.0.0.1. On your computer, open a tunnel as your sudo user and leave it running:
ssh -N -L 18789:127.0.0.1:18789 deploy@YOUR_SERVER_IP
Open http://127.0.0.1:18789/ in your browser. When it asks for the Gateway secret, print the token on the server and paste it in:
openclaw gateway auth-token --show
Treat the token as a password. If the dashboard asks for device approval, run openclaw devices list and openclaw devices approve YOUR_REQUEST_ID on the server.
Step 10: Connect a Telegram bot (optional)
In Telegram, message @BotFather, send /newbot, and copy the bot token it returns. Read the token without saving it to shell history, then add the channel:
read -rsp "Bot token: " TG_TOKEN && echo
openclaw channels add --channel telegram --token "$TG_TOKEN"
unset TG_TOKEN
openclaw channels status --probe
Send any message to your bot. Under the default pairing policy, the bot replies with a pairing code and does not run the agent until you approve it. Codes expire after 1 hour:
openclaw pairing list telegram
openclaw pairing approve telegram YOUR_PAIRING_CODE
Discord uses the same command with --channel discord and a bot token, after you enable the Message Content Intent and invite the bot to your server; see OpenClaw's Discord setup.
Step 11: Lock down OpenClaw security settings
The gateway binds to loopback by default. Set it explicitly, tighten file permissions, and run the security audit:
openclaw config set gateway.bind loopback
openclaw gateway restart
chmod 700 ~/.openclaw
chmod 600 ~/.openclaw/openclaw.json
openclaw security audit --deep
The audit reports open DM or group policies, exposed binds, short tokens and loose permissions. openclaw security audit --fix switches open group policies to allowlists and tightens file permissions.
- Keep Telegram's DM policy on
pairing. Theopenpolicy lets anyone who finds the bot trigger the agent's tools. - For a bot that other people message, start from OpenClaw's hardened baseline, which denies shell, file and automation tools by default.
Rotate the gateway token
Rotate the token if it was shared or pasted somewhere public. Set a new random value, restart, and print it:
openclaw config set gateway.auth.token "$(openssl rand -hex 32)"
openclaw gateway restart
openclaw gateway auth-token --show
Paste the new value into Gateway secret on each client, then confirm the old token no longer connects.
Step 12: Verify the gateway is not public
On the server, check the service, the listening address and the health endpoint:
openclaw gateway status
ss -tln | grep 18789
curl -fsS http://127.0.0.1:18789/healthz
The ss output looks similar to this. The local address must be 127.0.0.1 or [::1], never 0.0.0.0 or *:
LISTEN 0 511 127.0.0.1:18789 0.0.0.0:*
From your computer, with the tunnel closed, confirm the port is unreachable:
curl -m 5 http://YOUR_SERVER_IP:18789/healthz
The request times out. If it returns a response, check gateway.bind and sudo ufw status.
Install OpenClaw with Docker instead
OpenClaw publishes an official image, ghcr.io/openclaw/openclaw, and a Docker Compose setup script. This path replaces Steps 4 to 12; Steps 1 to 3 still apply. Install Docker Engine and the Compose plugin first and run these commands as deploy, added to the docker group.
Block published ports with DOCKER-USER rules
The Compose file publishes ports 18789, 18790 and 3978 on every interface, and Docker's rules bypass UFW. Before you start the container, append OpenClaw's documented DOCKER-USER block to /etc/ufw/after.rules:
sudo tee -a /etc/ufw/after.rules > /dev/null <<'EOF'
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
-A DOCKER-USER -s 127.0.0.0/8 -j RETURN
-A DOCKER-USER -s 10.0.0.0/8 -j RETURN
-A DOCKER-USER -s 172.16.0.0/12 -j RETURN
-A DOCKER-USER -s 192.168.0.0/16 -j RETURN
-A DOCKER-USER -s 100.64.0.0/10 -j RETURN
-A DOCKER-USER -p tcp --dport 80 -j RETURN
-A DOCKER-USER -p tcp --dport 443 -j RETURN
-A DOCKER-USER -m conntrack --ctstate NEW -j DROP
-A DOCKER-USER -j RETURN
COMMIT
EOF
sudo ufw reload
sudo iptables -S DOCKER-USER
sudo ip6tables -S DOCKER-USER
These rules drop new internet connections to published container ports except 80 and 443. If you enable IPv6 in Docker, add the same rules to /etc/ufw/after6.rules with IPv6 private ranges.
Run the Docker setup script
Clone the release tag that matches the image, pin the image, and run the setup script:
git clone --branch v2026.9.8 --depth 1 https://github.com/openclaw/openclaw.git
cd openclaw
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:2026.9.8"
./scripts/docker/setup.sh
The amd64 image is about 1.2 GB compressed. The script prompts for provider keys, writes a gateway token to .env, and starts the stack with restart: unless-stopped, so the gateway returns after a reboot. The container runs as the non-root node user and keeps state in ~/.openclaw on the host. Check it:
docker compose ps
curl -fsS http://127.0.0.1:18789/healthz
Compose publishes 18789 on every interface, so ss -tln shows 0.0.0.0:18789 on this path, and the DOCKER-USER rules drop new connections to it from the internet. If /etc/docker/daemon.json sets the loopback default from the Docker tutorial, ss -tln shows 127.0.0.1:18789 instead. In both cases, from your computer, with the tunnel closed, confirm that curl -m 5 http://YOUR_SERVER_IP:18789/healthz times out. Leave gateway.bind on lan, the value the setup script sets: loopback limits the gateway to the container's own network.
Open the dashboard and connect Telegram in Docker
Open the dashboard with the ssh -L tunnel command from Step 9 and the OPENCLAW_GATEWAY_TOKEN value from .env in the repository directory. Run OpenClaw commands through the openclaw-cli service. To connect Telegram:
read -rsp "Bot token: " TG_TOKEN && echo
docker compose run --rm openclaw-cli channels add --channel telegram --token "$TG_TOKEN"
unset TG_TOKEN
Send any message to the bot, then approve the pairing code:
docker compose run --rm openclaw-cli pairing list telegram
docker compose run --rm openclaw-cli pairing approve telegram YOUR_PAIRING_CODE
Update OpenClaw
Back up first (next section), then preview and apply the update as openclaw:
openclaw update --dry-run
openclaw update
openclaw --version
openclaw update checks the new release while the old gateway keeps serving, then restarts and verifies the service.
For Docker, run these as deploy. Replace YOUR_NEW_VERSION with a release number from OpenClaw's releases, such as 2026.9.8, without the leading v:
cd ~/openclaw
OC_VERSION="YOUR_NEW_VERSION"
git fetch --depth 1 origin tag "v$OC_VERSION"
git checkout "v$OC_VERSION"
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:$OC_VERSION"
OPENCLAW_SKIP_ONBOARDING=1 ./scripts/docker/setup.sh
docker compose run --rm openclaw-cli doctor --json
The setup script reads OPENCLAW_IMAGE only from the current shell. Without it, the script builds an image from source, which needs 6 GB RAM. These commands follow OpenClaw's Docker update steps.
Back up OpenClaw
OpenClaw keeps its state in SQLite databases under ~/.openclaw. Never copy the live .sqlite files; the backup command captures them safely and verifies the archive:
mkdir -p ~/backups && chmod 700 ~/backups
openclaw backup create --output ~/backups --verify
The archive holds provider keys, channel tokens and chat history. Store it encrypted, off the server. For whole-server copies, see VPS backups.
Stop or restart the OpenClaw gateway
Manage the service as openclaw:
openclaw gateway stop
openclaw gateway start
openclaw gateway restart
openclaw gateway stop leaves the unit enabled, so the gateway starts again at the next boot. To keep it off across reboots, disable the unit:
systemctl --user disable --now openclaw-gateway.service
For Docker, run docker compose stop openclaw-gateway in the repository directory.
Troubleshoot common OpenClaw errors
| Symptom | Cause | Fix |
|---|---|---|
openclaw: command not found | ~/.npm-global/bin is not on PATH | Run source ~/.bashrc or reopen sudo -iu openclaw |
$XDG_RUNTIME_DIR not defined from systemctl --user | The sudo -i shell has no runtime directory | Repeat the Step 5 export; check loginctl show-user openclaw --property=Linger prints Linger=yes |
unauthorized in the dashboard | The browser sent an old token | Paste the output of openclaw gateway auth-token --show |
administratively prohibited when the tunnel opens | SSH port forwarding is disabled | Put AllowTcpForwarding local in /etc/ssh/sshd_config.d/10-forwarding.conf (sshd reads that directory first), run sudo sshd -t, then sudo systemctl restart ssh |
Killed or exit code 137 | The server ran out of memory | Add the Step 2 swap file or move to more RAM |
For other problems, run openclaw doctor.
FAQ
What is the gateway for OpenClaw?
The gateway is OpenClaw's always-on process. It holds chat channel connections, routes messages to the model, runs tools, and serves the dashboard and API on port 18789, bound to 127.0.0.1 by default.
How do I enable the OpenClaw gateway?
Run openclaw gateway install as the user that owns OpenClaw. On Linux it writes and starts a systemd user service named openclaw-gateway. Enable lingering for that user so the gateway survives logouts and reboots.
How do I stop the OpenClaw gateway?
Run openclaw gateway stop as the service user. The unit stays enabled and starts at the next boot, so run systemctl --user disable --now openclaw-gateway.service to keep it off. For Docker, run docker compose stop.
How much RAM do I need to install OpenClaw on a VPS?
OpenClaw runs on 1 GB RAM with a swap file, and its docs recommend 2 GB or more when the model runs through an API. Building the Docker image from source needs 6 GB; the pre-built image skips that build.
Is OpenClaw free?
Yes. OpenClaw is open source under the MIT license. You pay for the server and for the model provider's API usage.
Is OpenClaw safe to run on a VPS?
Yes, with the gateway on loopback, a private token and the agent running as a user without sudo. Keep channels on pairing or allowlists, because anyone who can message the agent can trigger its tools.
Can I use a local LLM with OpenClaw?
Yes. Onboarding detects tool-capable models already installed in Ollama or LM Studio on the same server. CPU inference suits occasional, interactive replies; scheduled jobs and batch work belong on an API model.
Next steps
- Compare the two self-hosted agents in Hermes Agent vs OpenClaw: Key Differences for Self-Hosting.
- Reach the server over a private network with How to Set Up a WireGuard VPN Server on Ubuntu 24.04.
- Read OpenClaw's security documentation before you add tools or channels.
Cost Optimized plans run on AMD EPYC Milan 7003 Series processors up to 3.7 GHz with NVMe storage. Compare plans.
This work is licensed under CC BY-NC-SA 4.0.