Back to Insights
AI & Emerging Tech 11 min read

The Complete Guide to Deploying OpenClaw on an Ubuntu 24.04 VPS Securely

Step-by-step guide to deploying OpenClaw on Ubuntu 24.04 with production-ready security via Nginx, HTTPS, Ollama local LLM, and Gemini.

Overview

OpenClaw is an agentic AI runtime that allows you to run AI assistants via Telegram, Discord, and other chat channels. This guide covers the entire process from configuring your VPS, installing Ollama for local LLMs, to connecting OpenClaw with Telegram – ensuring a stable and secure production environment.

Stack Covered in This Guide:

  • Ubuntu 24.04 LTS
  • Node.js 22+
  • Ollama (local LLM inference)
  • OpenClaw 2026.3.x
  • Telegram Bot
  • Google Gemini CLI (primary cloud model)
graph TD
    User([User - Telegram / Discord]) -->|Internet| NG[Nginx Reverse Proxy: 443]
    NG -->|Localhost Auth| GW[OpenClaw Gateway: 18789]
    GW -->|Primary Inference| GM[Cloud: Google Gemini API]
    GW -->|Fallback Inference| OL[Local: Ollama Service 11434]
    
    style NG fill:#3b82f6,stroke:#1d4ed8,stroke-width:2px,color:#fff
    style GW fill:#8b5cf6,stroke:#7c3aed,stroke-width:2px,color:#fff
    style OL fill:#10b981,stroke:#047857,stroke-width:2px,color:#fff

Part 1: Preparing the VPS

1.1 Update the System

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git nano python3 ufw fail2ban

1.2 Create a Dedicated User for OpenClaw

Do not run OpenClaw as root. Create a dedicated user named claw:

sudo adduser claw

This command will prompt you for some information. Set a strong password for claw – write it down, as you’ll need it for the first sudo command. Fields like Full Name can be left blank.

sudo usermod -aG sudo claw
su - claw

Note: From this point forward, all commands should be run under the claw user. Commands that require root privileges will use sudo.

1.3 Fix the Hostname (To Avoid Sudo Errors)

Ensure the hostname is resolved correctly to prevent unable to resolve host warnings:

# Get the current hostname
hostname

# Add it to /etc/hosts if it isn't there already
sudo bash -c 'echo "127.0.1.1 $(hostname)" >> /etc/hosts'

1.4 Configure the Firewall (UFW)

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable

1.5 Generate an SSH Key

Perform this step on your local machine, not on the VPS:

ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/id_openclaw_vps
ssh-copy-id -i ~/.ssh/id_openclaw_vps.pub claw@<VPS_IP>

Verify the key login before disabling password auth:

ssh -i ~/.ssh/id_openclaw_vps claw@<VPS_IP>

1.6 Secure SSH

⚠️ Only do this after you have successfully verified SSH key login.

sudo nano /etc/ssh/sshd_config

Ensure the following lines are set:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
sudo systemctl restart ssh

1.7 Configure Fail2ban

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

1.8 Add Swap Space (Crucial for 8GB VPS)

Setting up a 2GB swap acts as a safety net to prevent sudden crashes when OpenClaw runs alongside Ollama and experiences short-term RAM spikes.

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

Part 2: Install Node.js

Use Node.js 22.x – this is the current LTS version.

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version

Part 3: Install Ollama

3.1 Install Ollama

curl -fsSL https://ollama.com/install.sh | sh

3.2 Configure the Ollama Service

export EDITOR=nano
sudo systemctl edit ollama

Add the following content:

[Service]
Environment="OLLAMA_NUM_PARALLEL=1"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_NUM_THREAD=2"
sudo systemctl daemon-reload
sudo systemctl enable ollama
sudo systemctl start ollama

3.3 Pull the Appropriate Model

We are using qwen3:1.7b-q8_0 in this guide – the strongest quantization of the Qwen3 1.7B model that still comfortably fits into 8GB of RAM.

ollama pull qwen3:1.7b-q8_0
ollama run qwen3:1.7b-q8_0 "hello"

Part 4: Install Google Gemini CLI

OpenClaw uses the Gemini CLI for cloud inference – this will act as the primary model.

sudo npm install -g @google/gemini-cli
sudo chown -R claw:claw /home/claw/.gemini

Log in with your Google account:

gemini

Choose 1. Sign in with Google. The Gemini CLI will output a URL – copy this URL, open it on your local machine, log into Google, then paste the authorization code back.


Part 5: Install OpenClaw

5.1 Install OpenClaw CLI

sudo npm install -g openclaw

5.2 Run Onboarding

openclaw onboard

Step 1 – Confirm personal use

I understand this is personal-by-default and shared/multi-user use requires lock-down. Continue?

Select Yes.

Step 2 – Setup mode

Setup mode
● QuickStart (Configure details later via openclaw configure.)
○ Manual

Select QuickStart – settings can be adjusted later with openclaw configure.

Step 3 – Model/auth provider

Model/auth provider
● Anthropic (Claude CLI + setup-token + API key)
○ ...
○ Ollama
○ Google
○ Skip for now

Select Skip for now – Gemini CLI and Ollama will be configured separately in Part 6.

Step 4 – Filter models by provider

Filter models by provider
● All providers
○ google-gemini-cli
○ ollama
○ ...

Select google-gemini-cli.

Step 5 – Model check

Model check
No auth configured for provider "google-gemini-cli". The agent may fail until
credentials are added. Run `openclaw models auth login --provider google-gemini-cli`,
`openclaw configure`, or set an API key env var.

Expected warning – credentials will be linked in Part 6.

Step 6 – Select channel

Select channel (QuickStart)
Telegram (Bot API)

Select Telegram (Bot API).

Step 7 – Provide bot token

How do you want to provide this Telegram bot token?
  Enter Telegram bot token

Select Enter Telegram bot token. Obtain a token from BotFather:

  1. Open Telegram, search @BotFather
  2. Send /newbot
  3. Set a display name (e.g., OpenClaw)
  4. Set a username (e.g., openclawbot) – must be unique across Telegram
  5. BotFather returns a token in the format 123456789:ABC-DEF... – copy the full string

Telegram DM access: The bot defaults to pairing DM policy – anyone can send a pairing request, but approval is required via openclaw pairing approve telegram <code>. To restrict access to yourself only:

# Get your Telegram user ID at: https://t.me/userinfobot
openclaw config set channels.telegram.dmPolicy "allowlist"
openclaw config set channels.telegram.allowFrom '["YOUR_USER_ID"]'

Step 8 – Web search provider

Search provider
● DuckDuckGo Search (experimental)
○ Brave Search
○ Exa Search
○ Skip for now

Select DuckDuckGo Search (experimental) – free, no API key required.

Step 9 – Optional API keys

Select No for all optional prompts – these can be configured later:

Set GOOGLE_PLACES_API_KEY for goplaces?  → No
Set NOTION_API_KEY for notion?           → No
Set OPENAI_API_KEY for openai-whisper?   → No
Set ELEVENLABS_API_KEY for sag?          → No

Step 10 – Onboarding completes automatically

The wizard performs the following without requiring input:

  • Saves config to ~/.openclaw/openclaw.json
  • Enables systemd lingering for the claw user (keeps gateway running after logout)
  • Installs the gateway service at ~/.config/systemd/user/openclaw-gateway.service
  • Starts the gateway and verifies Telegram connectivity

Expected output:

Telegram: ok (@openclawbot)
Agents: main (default)

Step 11 – Hatch the bot

How do you want to hatch your bot?
● Hatch in TUI (recommended)
○ Open the Web UI
○ Do this later

Select Hatch in TUI. The wizard launches the TUI and sends an initial message to the bot. An error will appear:

⚠️ Agent failed before reply: No API key found for provider "google-gemini-cli".

This is expected – OpenClaw has not yet been linked to Gemini CLI credentials. Exit the TUI with Ctrl+C and proceed to Part 6.


Part 6: Model Configuration

6.1 Add the Ollama provider

openclaw models auth add
  • Token provider: custom
  • Provider id: ollama
  • Profile id: ollama:local
  • Does this token expire?: No
  • Paste token: ollama

6.2 Fix Auth for Gemini CLI

openclaw models auth login --provider google-gemini-cli

Copy the OAuth URL, authenticate locally, and paste the redirect URL back.

6.3 Strategic Model Fallbacks

openclaw models set google-gemini-cli/gemini-2.5-flash
openclaw models fallbacks add ollama/qwen3:1.7b-q8_0

Note: If you have a VPS with 16GB RAM and a strong CPU, you can set Ollama as primary to save API costs. With 8GB RAM / 4 CPU, Gemini primary is the most practical choice.

6.4 Add Google Pro for Heavy Research Execution

/model google-gemini-cli/gemini-2.5-pro-preview

6.5 Verify Configuration

openclaw models list

Expected output:

Model                                      Input      Ctx      Local Auth  Tags
google-gemini-cli/gemini-2.5-flash         text+image 1024k    no    yes   default,configured
ollama/qwen3:1.7b-q8_0                     text       40k      yes   yes   fallback#1,configured
google-gemini-cli/gemini-2.5-pro-preview   text+image 1024k    no    yes   configured

Part 7: Tools Profile Setup

Drop processing complexities by using the lightweight tools profile:

openclaw config set tools.profile minimal

Part 8: Initiating the Gateway Layer

openclaw gateway restart
openclaw health

Test your bot on Telegram via text. It will prompt for pairing. Run this on your VPS to accept the pairing request:

openclaw pairing approve telegram {KEY}

Part 9: Expose Web UI via Subdomain

9.1 Address Configuration Resolution

Add an A record pointing claw.your-domain.com to your VPS IP.

9.2 Gateway Firewall Exceptions

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

9.3 Implement Nginx + Certbot

sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/openclaw
server {
    listen 80;
    server_name claw.your-domain.com;

    location / {
        proxy_pass http://127.0.0.1:18789;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
sudo ln -s /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

9.4 Enable SSL

sudo certbot --nginx -d claw.your-domain.com

9.5 Gateway Enhancements

openclaw config set gateway.controlUi.allowedOrigins '["https://claw.your-domain.com"]'
openclaw config set gateway.trustedProxies '["127.0.0.1"]'
openclaw config set gateway.auth.mode "token"
openclaw gateway restart

Retrieve the authorized UI URL:

python3 -c "import json; d=json.load(open('/home/claw/.openclaw/openclaw.json')); print('https://claw.your-domain.com/#token=' + d['gateway']['auth']['token'])"

If it still throws a pairing required loop over the proxy, switch to Basic Auth.

9.6 Nginx Basic Auth (Optional Fallback)

If token-based auth produces a pairing required loop through Nginx, disable it and use HTTP Basic Auth instead:

openclaw config set gateway.auth.mode "none"
openclaw gateway restart
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd your-username

Edit /etc/nginx/sites-available/openclaw and add these two lines inside the location / block:

auth_basic "OpenClaw";
auth_basic_user_file /etc/nginx/.htpasswd;
sudo nginx -t
sudo systemctl reload nginx

9.7 Fail2ban for Nginx

Block brute-force attempts against Basic Auth:

sudo nano /etc/fail2ban/jail.local

Add:

[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-http-auth

After 5 failed password attempts, the source IP is banned for 1 hour.

9.8 Accessing the Web UI

Open https://claw.your-domain.com in a browser. The browser will prompt for Basic Auth credentials.

After passing Basic Auth, leave both the Gateway Token and Password fields empty and click Connect.

Note: Basic Auth has no session timeout – the browser caches credentials until it is fully closed or the cache is cleared. Use an Incognito/Private window if you want to be prompted each session.


Part 10: Monitoring & Troubleshooting

Real-time Logs

openclaw logs --follow

Monitor Hardware

free -h
top -bn1 | head -5

Session System Wipes

echo '{}' > ~/.openclaw/agents/main/sessions/sessions.json
rm -f ~/.openclaw/agents/main/sessions/*.jsonl
openclaw gateway restart

Common Errors

ErrorCauseFix
OOM: model requires X GiBModel too large for available RAMUse a smaller quantization or smaller model
typing TTL reached (2m)CPU inference too slowSwitch Gemini to primary
404 model_not_foundIncorrect model nameVerify with openclaw models list
429 No capacityGoogle API overloadWait or switch to Ollama
[xai-auth] bootstrap config fallback: no config-backed key foundOpenClaw looking for xAI/Grok configSafe to ignore if xAI is not in use

Part 11: Decisive AI Model Selections

ModelQuantSizeRequired RAMVietnameseTool CallingSweet Spot
qwen3:1.7bq4_K_M~1.5GB~2GBGoodFairVPS 8GB + additional heavy services
qwen3:1.7bq8_0~2.3GB~3GBGoodFairVPS 8GB (general use)
qwen2.5:3b-instructq4_K_M~1.9GB~2.5GBGoodGoodSolid sweet spot for 8GB nodes
qwen2.5:3b-instructq8_0~3.3GB~4GBGoodGoodVPS 16GB
qwen2.5:7b-instructq4_K_M~5.2GB~6.5GBGoodGoodVPS 16GB Dedicated

On an 8GB VPS with OpenClaw active (~4.5–5GB RAM), the safest options are qwen2.5:3b-instruct-q4_K_M or qwen3:1.7b-q8_0.


Conclusion

This setup runs on 3 tiers:

  1. Primary – Gemini 2.5 Flash (cloud, fast, 1024k context)
  2. Fallback – Ollama local (offline-capable, zero-cost)
  3. On-demand – Gemini Pro for explicit heavy research queries

Guide written based on empirical OpenClaw deployment operations inside 4 CPU / 8GB RAM instances.