Setting Up Clawdbot/OpenClaw on a VPS or Local Machine
Install and run a Clawdbot/OpenClaw-style personal agent host: a long-running process with config, secrets, one chat connector, and automatic restart.
This is a runtime recipe, not a product install manual. Concrete projects change CLIs and paths; verify any third-party project's docs at build time. The architecture stays stable.
Summary
Run a dedicated OS user (or container), put secrets in env files outside git, start the host under a process supervisor, expose only the ports you need, and smoke-test with an allowlisted chat user before adding tools.
Recipe
- Pick a placement. Laptop for experiments; small VPS for always-on chat control; container on either for easier wipe/rebuild.
- Create an isolated identity. Dedicated OS user or rootless container. No sudo for the agent process.
- Provision runtime deps. Language runtime (for example Python 3.11+), process supervisor (
systemd, Docker, or launchd), and firewall basics. - Lay out directories. Config, data (prefs/memory), logs, and secrets as separate paths with tight permissions.
- Configure the minimum agent. Model base URL + key, one chat bot token, allowlisted sender ids,
max_turns, pause flag path. - Install as a service. Restart on failure; start on boot only after you accept the security surface.
- Smoke-test. Send a ping from the allowlisted account; confirm reject/ignore from a non-allowlisted id; confirm
/pauseworks. - Harden before tools. SSH keys only, unattended upgrades or a patch cadence, backups for data dir, documented wipe steps.
Working Example
Directory layout and a minimal host entrypoint (illustrative):
~/personal-agent/
app/main.py
config/agent.toml # non-secret settings
data/prefs.json
data/tasks/
logs/
secrets/agent.env # chmod 600; never commit# secrets/agent.env (example keys - names vary by project)
MODEL_BASE_URL=https://openrouter.ai/api/v1
MODEL_API_KEY=sk-or-...
MODEL_ID=openai/gpt-4o-mini
TELEGRAM_BOT_TOKEN=...
ALLOWED_SENDER_IDS=123456789
MAX_TURNS=6
DATA_DIR=/home/agent/personal-agent/data# app/main.py - sketch of a long-running host loop
import os
import time
from pathlib import Path
DATA = Path(os.environ["DATA_DIR"])
PAUSED = DATA / "PAUSED"
def poll_once() -> None:
if PAUSED.exists():
return
# 1) pull updates from chat adapter
# 2) authorize sender
# 3) run bounded agent loop
# 4) post reply
pass
def main() -> None:
DATA.mkdir(parents=True, exist_ok=True)
while True:
try:
poll_once()
except Exception:
# log + continue; supervisor restarts on hard crash
pass
time.sleep(1)
if __name__ == "__main__":
main()Example systemd unit (Linux VPS or desktop):
# /etc/systemd/system/personal-agent.service
[Unit]
Description=Personal agent host
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=agent
Group=agent
WorkingDirectory=/home/agent/personal-agent
EnvironmentFile=/home/agent/personal-agent/secrets/agent.env
ExecStart=/home/agent/personal-agent/.venv/bin/python app/main.py
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now personal-agent
sudo systemctl status personal-agent
journalctl -u personal-agent -fDocker-shaped alternative (same env file pattern):
docker run -d --name personal-agent --restart unless-stopped \
--env-file ./secrets/agent.env \
-v "$(pwd)/data:/data" \
your-image:tagVerify image contents and tags at build; do not run privileged or mount the Docker socket.
Deep Dive
Local machine vs VPS
| Concern | Local | VPS |
|---|---|---|
| Uptime | Sleeps with the machine | Always reachable |
| Network | Often behind NAT; webhooks harder | Public IP; lock SSH and ports |
| Physical access | You control the disk | Provider staff + hypervisor trust |
| Latency to you | Excellent when open | Depends on region |
| First week fit | Learning the loop | Daily remote control |
Start local if you are still changing code every hour. Move to a VPS when chat-driven access while away matters more than laptop privacy locality.
What "install" means for this pattern
Clawdbot/OpenClaw-style setups are less like apt install assistant and more like deploying a small service:
- Binary or app checkout (language project, container image, or release tarball - project-specific).
- Config for connectors and model routing.
- Secrets for tokens.
- Supervisor so the process returns after reboot and crash.
- Data volume so prefs and memory survive redeploys.
If a project only gives you a CLI chat REPL with no supervisor story, you still need steps 4-5 yourself for a true personal agent host.
Network exposure
Day one: outbound-only host that long-polls Telegram (or similar) needs no inbound public ports for chat.
Add inbound only when you use webhooks, a web UI, or health checks. Then terminate TLS, bind to localhost + reverse proxy, or restrict by firewall allowlist.
SSH on a VPS: keys only, non-default user, fail2ban or equivalent, no password auth.
Config vs secrets vs data
- Config: model id defaults, max turns, quiet hours, feature flags - may be in git if non-sensitive.
- Secrets: bot tokens, OAuth client secrets, API keys - never git;
chmod 600; rotate on leak. - Data: prefs, task state, memory indexes - backed up; encrypted at rest when the host is shared or cloud-hosted.
Smoke-test checklist
- Process stays up for 10+ minutes under the supervisor.
- Allowlisted sender gets a coherent reply.
- Non-allowlisted sender cannot invoke the model (silent or static deny).
- Restart (
systemctl restart/ container recreate) keeps prefs on the data volume. - Pause flag or
/pausestops tool work without redeploy. - Logs contain no raw tokens.
Gotchas
- Running as your primary login user. The agent inherits browser cookies, SSH keys, and cloud CLIs. Use a dedicated user or container.
- Secrets in the repo.
.envcommitted once is a permanent rotation event. - No restart policy. A crash overnight means a "dead" personal agent you only notice at 9am.
- Webhook without TLS or auth. Inbound HTTP is an attack path; prefer poll modes until you can terminate TLS properly.
- Open firewall "for debugging." Temporary
0.0.0.0/0rules become permanent. - Data on container writable layer. Recreate the container and lose memory unless you mounted a volume.
- Enabling shell or mail on first boot. Prove host stability and allowlisting before expanding blast radius.
- Assuming project defaults are safe. Defaults optimize for demos; personal production needs deny-by-default senders and budgets.
Alternatives
| Approach | Pros | Cons |
|---|---|---|
| Local process + terminal | Fast iteration | No always-on; weak remote UX |
systemd user or system service | Native Linux, simple logs | Host-specific setup |
| Docker/Podman | Rebuild/wipe easy | Volume and network config discipline |
| Managed container host | Less OS babysitting | Another trust boundary + cost |
| Fully local model runtime | Data locality | GPU/CPU cost; quality variance |
| Hosted personal assistant SaaS | Lowest ops | Less control over tools and retention |
FAQs
Do I need Clawdbot or OpenClaw specifically?
No. Use any runtime that gives you a long-running host, connectors, tools, and memory. Those names label the architecture pattern this recipe targets.
What size VPS is enough?
For chat + model API calls, a small shared CPU instance with 1-2 GB RAM often suffices. Local models or browser automation need far more - size for tools, not for the chat adapter.
Should I use Docker on day one?
If you already think in images, yes. If not, a venv + systemd unit is enough to learn. Containerize before you depend on hard-to-rebuild host snowflakes.
How do I update the agent safely?
Deploy to a second directory or new image tag, run smoke tests, then switch the service symlink or container name. Keep the data volume untouched across app upgrades.
What about Windows or macOS hosts?
Same layout: dedicated user if possible, env-based secrets, a login item or service manager (Task Scheduler, launchd) for restart. Path and firewall details differ; the mental model does not.
When should I enable start-on-boot?
After allowlisting and pause work, and after you accept that a compromised host can act whenever the machine is on.
How do I handle HTTPS webhooks on a home connection?
Use a tunnel or reverse proxy you understand, or prefer poll-based adapters. Do not port-forward the agent process raw to the internet.
Where should logs go?
Supervisor journal or rotated files under logs/. Redact tokens; cap size so verbose tool dumps cannot fill the disk.
What is the first tool to add after setup?
Usually none. Add a second chat-free path only when needed; otherwise add read-only mail or calendar after a week of stable chat-only use.
How do I wipe a compromised host?
Stop the service, revoke bot and model keys, revoke OAuth apps, destroy the data volume if untrusted, reprovision the OS or container, restore prefs from a clean backup only after review.
Related
- The Self-Hosted Personal Agent Mental Model - what you are installing
- Self-Hosted Personal Agents Basics - first loop sketches
- Connecting Discord, Slack, Telegram, and WhatsApp Integrations - next connector work
- Backend Flexibility: Routing a Personal Agent Through OpenRouter - model backend config
- Self-Hosted Personal Agents Best Practices - ongoing hardening
- Why Self-Hosting a Personal Agent Appeals to Privacy-Conscious Users - trust-boundary trade-offs
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.