OpenClaw is a self-hosted agent gateway: sessions, tools, and (optional) chat channels. The GPU is not for that control plane. The GPU is for the local model that OpenClaw calls. This guide launches a Massed Compute GPU VM, binds Ollama and the OpenClaw Gateway to loopback, and runs a real tool-using agent turn against a private 14B model.
Search intent is self-host OpenClaw with a local LLM — not a hosted API key. This was validated on an NVIDIA L40 (48 GB) on August 25, 2026.
vLLM and SGLang also work as OpenAI-compatible backends. This walkthrough uses Ollama’s native API (http://127.0.0.1:11434, no /v1) because that path keeps tool calling intact. Do not copy the SGLang or vLLM install commands into this stack.
A later cluster post covers a Hermes Kanban + Ollama multi-agent team. Name it only — that is a different recipe.
| Component | Version | Purpose |
|---|---|---|
| Ubuntu Server | 24.04 LTS | Image 184: NVIDIA driver 580.126.16 |
| OpenClaw | 2026.7.1-2 | Gateway + openclaw agent CLI |
| Node.js | 26.7.0 | Runtime the installer provisioned |
| Ollama | 0.32.15 | Local inference, native /api/chat |
| Model (validated) | qwen2.5:14b |
14.8B, Q4_K_M, 32,768 ctx, tools capability |
| Nginx | 1.24.0 | Optional loopback HTTP basic-auth gate to the Control UI |
| UFW | active | SSH (22/tcp) only |
| Resource | This walkthrough | Notes |
|---|---|---|
| GPU | L40 48 GB (gpu_1x_l40) |
Validated. 14B Q4 used ~15.1 GB; the card is for Ollama, not Node |
| System RAM | 72 GB | SKU ships 72 GiB |
| vCPU | 14 | SKU ships 14 vCPU |
| Storage | 625 GB | qwen2.5:14b pull was 9.0 GB |
| Network | 1 Gbps | First ollama pull plus the OpenClaw npm package |
Massed Compute VM Pricing
Lead with the L40 this guide was tested on. 80 GB cards are listed for 70B-class local models we did not run here.
Pricing fetched from the Massed Compute inventory API on August 25, 2026.
| SKU | Description | vCPU | RAM | Storage | Price | Capacity |
|---|---|---|---|---|---|---|
gpu_1x_l40_spot |
1x L40 (48GB) [Spot] | 14 | 72 GiB | 625 GB | $0.78/hr | 21 |
gpu_1x_6000_ada |
1x RTX 6000 ADA (48GB) | 12 | 72 GiB | 350 GB | $0.79/hr | 4 |
gpu_1x_l40 |
1x L40 (48GB) | 14 | 72 GiB | 625 GB | $0.86/hr | 21 |
gpu_1x_A100_SXM4 |
1x A100 SXM4 (80GB) | 14 | 100 GiB | 625 GB | $1.38/hr | 10 |
gpu_1x_DGX_A100 |
1x DGX A100 (80GB) | 16 | 120 GiB | 1000 GB | $1.38/hr | 2 |
gpu_1x_l40. Use on-demand if the agent session cannot restart. The L40 is the card this run used — see NVIDIA L40 GPU Best Use Cases. For 80 GB local 70B see NVIDIA A100 GPU Best Use Cases. Inference card sizing: The Best GPU for LLM Inference Without Overpaying. Serving the same weights through SGLang or vLLM is a different post.Step-by-Step Deployment
Image 184 logs in as Ubuntu (capital U). If SSH offers extra keys and then fails, add -o IdentitiesOnly=yes.
Launch GPU VM
# Launch via Massed Compute dashboard or API
# Product: gpu_1x_l40
# Image: 184 (Ubuntu Server 24.04 w/ Drivers)
# SSH Key: attach your public key
# Instance name: openclaw-local-llm
Verify the GPU
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP \
'nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader'
This run printed NVIDIA L40, 46068 MiB, 580.126.16.
Install Ollama on loopback
The GPU workload is Ollama. Bind it to 127.0.0.1 so the model API is not on the public interface.
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
curl -fsSL https://ollama.com/install.sh | sh
sudo mkdir -p /etc/systemd/system/ollama.service.d
sudo tee /etc/systemd/system/ollama.service.d/override.conf >/dev/null <<'CONF'
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
CONF
sudo systemctl daemon-reload
sudo systemctl enable --now ollama
sudo systemctl restart ollama
ss -ltn | grep 11434
curl -sS http://127.0.0.1:11434/api/tags
ollama --version
EOF
You should see 127.0.0.1:11434 and ollama version is 0.32.15 (or the version you actually installed that day).
Pull a tool-capable local model
OpenClaw prefers an installed model with tools and a context window of at least 16K. This guide uses ungated qwen2.5:14b (32K, tools).
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
ollama pull qwen2.5:14b
ollama show qwen2.5:14b | sed -n '/Capabilities/,/System/p'
EOF
This pull was 9.0 GB. ollama show reported completion and tools. Swap the tag if you want a smaller 7B (qwen2.5:7b) or a larger 32B on the same 48 GB card.
Ollama-only setup, without OpenClaw, is already covered in Deploy LLMs with Ollama on GPU Cloud.
Install OpenClaw
The published installer provisions Node if the image does not have it. Skip the interactive wizard; onboard next.
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard
export PATH="$HOME/.npm-global/bin:$PATH"
openclaw --version
node -v
EOF
This VM installed OpenClaw 2026.7.1-2 and Node.js v26.7.0. If openclaw is missing in a new shell, source ~/.bashrc or prepend ~/.npm-global/bin as above. Pin the version you print from openclaw --version — do not copy an older npm tag from a gist.
Onboard: local Ollama + loopback Gateway
--gateway-bind loopback keeps the Control UI and WebSocket on 127.0.0.1:18789. --install-daemon writes a systemd user unit and enables lingering so the Gateway survives logout.
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
export PATH="$HOME/.npm-global/bin:$PATH"
openclaw onboard --non-interactive --accept-risk \
--mode local \
--auth-choice ollama \
--custom-base-url "http://127.0.0.1:11434" \
--custom-model-id "qwen2.5:14b" \
--gateway-bind loopback \
--install-daemon \
--skip-skills
openclaw gateway status
ss -ltn | grep 18789
EOF
Expected: Gateway: bind=loopback (127.0.0.1), port=18789, Connectivity probe: ok. Config lands in ~/.openclaw/openclaw.json. Primary model should be ollama/qwen2.5:14b. Tools profile on this run was coding (read / write / exec).
Do not set Ollama baseUrl to http://127.0.0.1:11434/v1. OpenClaw’s Ollama provider uses the native API. The OpenAI-compat /v1 URL breaks tool calling.
Optional: turn off hosted memory search if you have no OpenAI key:
openclaw config set agents.defaults.memorySearch.enabled false
Reach the Control UI from your laptop with an SSH tunnel, not a public bind:
ssh -o IdentitiesOnly=yes -N -L 18789:127.0.0.1:18789 Ubuntu@YOUR_VM_IP
# then open http://127.0.0.1:18789/ locally
The Gateway still expects its token over the tunnel. openclaw dashboard on the VM is the same origin.
Firewall and optional auth gate
Default incoming deny. Only SSH is public. Ollama 11434 and OpenClaw 18789 stay on loopback.
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
echo y | sudo ufw enable
sudo ufw status
EOF
If you later expose the Control UI, put HTTP basic auth in front (and TLS before it faces the internet). This validation listened on 127.0.0.1:8080 only — not 0.0.0.0. Unauthenticated curl returned 401; authenticated curl returned 200.
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
sudo apt-get update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y nginx apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd YOUR_USER
sudo chown root:www-data /etc/nginx/.htpasswd
sudo chmod 640 /etc/nginx/.htpasswd
sudo tee /etc/nginx/sites-available/authproxy >/dev/null <<'NGX'
server {
listen 127.0.0.1:8080;
server_name _;
location / {
auth_basic "OpenClaw";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:18789;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 3600s;
}
}
NGX
sudo ln -sf /etc/nginx/sites-available/authproxy /etc/nginx/sites-enabled/authproxy
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/
EOF
htpasswd -c prompts for a password. Do not paste credentials into chat or tickets. For a public listener you still need TLS; basic auth on plaintext HTTP is not enough.
Run a real agent workflow
Not “hello”. Seed a workspace ticket, then ask the agent to use exec against it and write report.md.
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'bash -s' <<'EOF'
set -euo pipefail
export PATH="$HOME/.npm-global/bin:$PATH"
cat > ~/.openclaw/workspace/ops-ticket.md <<'TICKET'
# GPU sizing ticket
SKUs:
- gpu_1x_l40
- gpu_1x_l40s
- gpu_1x_A100_SXM4
TICKET
openclaw agent --agent main --timeout 180 --json --session-id sku-report \
--message 'Use exec once: awk '\''/^- gpu_/{print; c++} END{print "COUNT=" c}'\'' ~/.openclaw/workspace/ops-ticket.md > ~/.openclaw/workspace/report.md && echo RECOMMEND: gpu_1x_l40 for 14B Q4 on 48GB >> ~/.openclaw/workspace/report.md && cat ~/.openclaw/workspace/report.md
Do not invent SKUs.'
cat ~/.openclaw/workspace/report.md
EOF
This L40 produced:
- gpu_1x_l40
- gpu_1x_l40s
- gpu_1x_A100_SXM4
COUNT=3
RECOMMEND: gpu_1x_l40 for 14B Q4 on 48GB
openclaw agent JSON on that turn: toolSummary.calls=1, tool exec, failures=0, provider ollama, model qwen2.5:14b, wall 10.99 s with the model already resident. An earlier turn also issued read + write + exec (four calls, 69.65 s including first load). If the model fires several tools in parallel before seeing read output, it can grep the wrong pattern — wait for the file contents, or pin a single exec as above.
Persistence: workspace files live under ~/.openclaw/workspace/. Sessions are under ~/.openclaw/agents/main/sessions/. The Gateway is the user systemd unit openclaw-gateway.service.
Confirm GPU utilization
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP \
'nvidia-smi --query-gpu=name,memory.used,utilization.gpu --format=csv,noheader; nvidia-smi'
After the agent turns this L40 showed 15099 MiB used of 46068, 36% util, ~241 W. The compute process was ollama llama-server (~15090 MiB). The OpenClaw Gateway is a Node process on CPU. That is the split: GPU = model, CPU = agent control plane.
OpenClaw + local model vs hosted APIs vs Hermes
| Path | Model location | GPU for | Use this post? |
|---|---|---|---|
| OpenClaw + local Ollama | Same VM (or a second inference VM on 127.0.0.1 / private net) | Weights + KV cache | Yes — this guide |
| OpenClaw + hosted API | Anthropic / OpenAI / cloud | None required | Onboard with an API key instead of --auth-choice ollama |
| OpenClaw + vLLM / SGLang | Local OpenAI-compat /v1 |
Same as a serve post | Wire baseUrl to the vLLM or SGLang endpoint; still bind loopback |
| Hermes Kanban team | Local Ollama + multi-agent workers | Model, plus orchestration | Later cluster post — do not copy that stack here |
Hosted inference is simpler. Local inference keeps prompts, tools, and files on the VM. This article is the local path.
VRAM / GPU tier
The OpenClaw Gateway does not need a GPU. Size the SKU for the model and context, not for Node.
| Local model | This article | SKU |
|---|---|---|
| 7B Q4 | Not this run. Typical ~5–8 GB | 24 GB works; 48 GB is comfortable |
| 14B Q4 | Measured: 15099 MiB used on L40 | gpu_1x_l40 (48 GB) |
| 32B Q4 | Not run. Typical ~18–22 GB | 48 GB |
| 70B Q4 | Not run | 80 GB A100 / H100, or 2×48 GB |
CTA matches the demonstrated 14B-on-L40: launch gpu_1x_l40. Longer context or a 70B local brain wants the 80 GB row.
Measured result
Same L40, OpenClaw 2026.7.1-2, Ollama 0.32.15, qwen2.5:14b Q4_K_M, August 25, 2026.
| Metric | Value |
|---|---|
Idle nvidia-smi used |
0 MiB |
| After agent turns | 15099 MiB / 46068 MiB |
| GPU util (during second turn) | 36% |
| Process | ollama llama-server ~15090 MiB |
| First agent wall (read/exec/write, cold load) | 69.65 s |
| Second agent wall (exec, model resident) | 10.99 s |
| Second-turn tools | exec ×1, failures 0 |
| Workspace artifact | report.md with COUNT=3 and the three SKUs |
| Listeners | 127.0.0.1:11434, 127.0.0.1:18789, 127.0.0.1:8080 |
| UFW | 22/tcp only |
No hosted-API bake-off. No Hermes workflow. No invented tok/s vs vLLM.
Troubleshooting
SSH fails or keeps asking for a password. Image 184’s user is Ubuntu, not ubuntu. Use -o IdentitiesOnly=yes. Refresh host keys with ssh-keygen -R YOUR_VM_IP if the instance was relaunched on a reused IP.
openclaw: command not found. The installer put the binary in ~/.npm-global/bin. source ~/.bashrc or export that PATH.
Tool calls print raw JSON instead of running tools. You pointed OpenClaw at Ollama /v1. Use baseUrl: "http://127.0.0.1:11434" and api: "ollama".
Laptop browser cannot open port 18789 on the VM IP. Expected with loopback bind. SSH-tunnel, or add nginx + TLS + auth before binding 0.0.0.0.
refusing to bind gateway … without auth. Non-loopback bind requires a Gateway token (or equivalent). Do not disable auth to “make it work.”
Agent invents SKUs / greps the wrong pattern. Parallel tool calls can fire exec before read returns. Pin one exec, or tell the model to read first and write only after the file contents are in the tool result.
Ollama on 0.0.0.0. Check /etc/systemd/system/ollama.service.d/override.conf for OLLAMA_HOST=127.0.0.1:11434. Do not expose an unauthenticated model API.
Out of memory on 32B / 70B. This run is 14B Q4 on 48 GB. Move up a SKU or a smaller quant. See the VRAM table.
Gemma / cloud model IDs in openclaw.json. Onboard may list a suggested catalog entry you did not pull. Set agents.defaults.model.primary to ollama/qwen2.5:14b (or your pulled tag).
Deploy OpenClaw with a Private Local LLM
Launch NVIDIA L40 instances sized for a local OpenClaw model. Get 48GB VRAM, NVMe storage, and per-second billing.
Think it. Build it. Scale it.
Quick Setup Reference
# 1. Launch gpu_1x_l40, image 184
# 2. Verify GPU
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'nvidia-smi'
# 3. Ollama on 127.0.0.1 + pull
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'curl -fsSL https://ollama.com/install.sh | sh'
# set OLLAMA_HOST=127.0.0.1:11434 via systemd drop-in, then:
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP 'ollama pull qwen2.5:14b'
# 4. OpenClaw
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP \
'curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard'
# onboard --auth-choice ollama --gateway-bind loopback --install-daemon
# 5. Agent
ssh -o IdentitiesOnly=yes Ubuntu@YOUR_VM_IP \
'PATH=$HOME/.npm-global/bin:$PATH openclaw agent --agent main --message "…"'
Frequently Asked Questions
01What did this guide actually run?
gpu_1x_l40, image 184, OpenClaw 2026.7.1-2, Ollama 0.32.15, qwen2.5:14b Q4_K_M. Gateway and Ollama on 127.0.0.1. Agent exec wrote report.md with COUNT=3. Peak used 15099 MiB.
02Why is the GPU for the model, not OpenClaw?
OpenClaw’s Gateway is Node. nvidia-smi showed llama-server holding the VRAM. Size the VM for the weights and context you load into Ollama (or vLLM / SGLang).
03Should I use vLLM or SGLang instead of Ollama?
Use Ollama for this single-user agent path and native tool calling. Use vLLM or SGLang when you want a production OpenAI /v1 server, then point OpenClaw at that loopback URL. This VM did not measure a throughput bake-off.
04Can I put the model on a second GPU VM?
Yes. Keep the inference bind private (loopback + tunnel, or VPC / allowlist). Set --custom-base-url to that host without /v1 if it is Ollama. Do not leave an open unauthenticated API on 0.0.0.0.
05Is this the Hermes local-AGI recipe?
No. Hermes Kanban + a Llama worker team is a different later post. This post is OpenClaw + one local model + tools.
06Do I need a Hugging Face token?
Not for qwen2.5:14b from Ollama. Gated GGUF or Hugging Face weights need whatever auth that runtime requires.
07What’s the difference between spot and on-demand?
Spot is cheaper and can be interrupted. This run used on-demand gpu_1x_l40. Use on-demand if a long agent session cannot restart.
Recipe tested on August 25, 2026.











