essay

Self-Hosted AI Agent on Hetzner: A Complete OpenClaw Setup Guide

April 11, 2026

Estimated setup time: 45–60 minutes
Monthly cost: ~€20–45 (Hetzner + Anthropic API)
Difficulty: Intermediate (comfortable with SSH/CLI)
Prerequisites: Hetzner account, Anthropic API key, Telegram account
Covers: News summaries, stock tracking, flight alerts, spend tracking


OpenClaw is a self-hosted AI agent gateway that connects messaging apps (Telegram, WhatsApp, Discord) to Claude. Unlike SaaS alternatives, everything runs on your own server — your data stays under your control.

This guide walks through:

  1. Provisioning a secure Hetzner VPS
  2. Installing OpenClaw with Docker isolation
  3. Connecting Telegram as your messaging interface
  4. Configuring Claude (claude-sonnet-4-6) as the AI backend
  5. Setting up Tailscale for secure remote access
  6. Configuring four automation use cases
  7. Hardening the setup for production use

Architecture

Your Phone (Telegram)
│
│  (Telegram Bot API — encrypted in transit)
ā–¼
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  Hetzner CX22 VPS  (Berlin/Nuremberg)   │
│                                         │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    │
│  │  Docker Container: OpenClaw     │    │
│  │  - Gateway (port 18789)         │    │
│  │  - Session state & memory       │    │
│  │  - Skills & HEARTBEAT tasks     │    │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜    │
│             │                           │
│             │ API calls                 │
│             ā–¼                           │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    │
│  │  Anthropic API (claude-sonnet-4-6)   │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜    │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
│  Tailscale VPN
│  (private access only — port never public)
ā–¼
Your Laptop / Other Devices

Key security principle: the OpenClaw gateway port (18789) is never exposed to the public internet. All access goes through Tailscale's encrypted VPN tunnel. Your Telegram bot token is the only external entry point.


Part 1 — Hetzner VPS Setup

1.1 Create Your Server

Log in to Hetzner Cloud → New Project → Add Server.

SettingValue
Server typeCX22 (2 vCPU, 4GB RAM, 40GB SSD) — ~€4.15/month
ImageUbuntu 24.04 LTS
LocationNuremberg or Falkenstein (lowest latency from Berlin)
SSH KeyAdd your public key (ssh-keygen -t ed25519 if needed)
BackupsEnable (adds 20% to cost — worth it)
FirewallCreate new (configured in next step)

1.2 Configure the Hetzner Firewall

In Hetzner console → Firewalls → Create Firewall. Add these inbound rules:

ProtocolPortSourcePurpose
TCP22Your IP onlySSH access
TCP41641AnyTailscale VPN (WireGuard)

To find your home IP: curl ifconfig.me. Do not open port 18789 — access will go through Tailscale.

1.3 Initial Server Configuration

SSH in and run these commands in order:

# Connect and update
ssh root@<YOUR_SERVER_IP>

apt update && apt upgrade -y
apt install -y curl wget git ufw unattended-upgrades apt-transport-https ca-certificates gnupg

Enable automatic security updates:

dpkg-reconfigure --priority=low unattended-upgrades
# Select 'Yes' when prompted

Create a non-root user:

adduser shahul
usermod -aG sudo shahul
rsync --archive --chown=shahul:shahul ~/.ssh /home/shahul

# Disable root SSH login
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd

Configure UFW firewall:

ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 41641/tcp    # Tailscale
# DO NOT open 18789 here — Tailscale handles that
ufw --force enable
ufw status

Log out and back in as your new user before continuing: ssh shahul@<YOUR_SERVER_IP>


Part 2 — Docker & Tailscale Installation

2.1 Install Docker

# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg

# Add Docker repository
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list

# Install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Add your user to docker group (no sudo needed)
sudo usermod -aG docker $USER

# Verify
docker --version
# Expected: Docker version 26.x.x or later

Log out and back in after this step for docker group permissions to take effect.

2.2 Install and Configure Tailscale

Tailscale creates an encrypted VPN tunnel between your devices, replacing the need to expose any ports to the internet.

# Install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh

# Authenticate (opens a browser URL)
sudo tailscale up

# Note your Tailscale IP — e.g. 100.x.x.x
tailscale ip -4

Also install Tailscale on your phone and laptop from tailscale.com/download. Once all devices are connected to the same account, they share a private network.


Part 3 — Telegram Bot Setup

3.1 Create a Telegram Bot

  1. Open Telegram and search for @BotFather
  2. Send: /newbot
  3. Enter a name (e.g. "My Jarvis") and a username ending in bot (e.g. shahul_jarvis_bot)
  4. BotFather replies with a token: 7312345678:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  5. Copy and save this token securely

3.2 Get Your Telegram User ID

  1. Search for @userinfobot on Telegram
  2. Send any message — it replies with your numeric ID (e.g. 123456789)
  3. Save this number — you'll add it to the allowlist

Never share your bot token. If leaked, revoke it immediately via @BotFather → /revoke.


Part 4 — Node.js & OpenClaw Installation

4.1 Install Node.js 22

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

node --version    # Should show v22.x.x
npm --version     # Should show 10.x.x

4.2 Install OpenClaw

npm install -g openclaw@latest
openclaw --version

4.3 Run the Onboarding Wizard

Have your Anthropic API key and Telegram bot token ready.

openclaw onboard --install-daemon

The wizard will ask:

PromptRecommended answer
Agent nameJarvis (or anything you like)
AI providerAnthropic
API keyFrom console.anthropic.com
Modelclaude-sonnet-4-6
Messaging channelTelegram
Telegram bot tokenFrom @BotFather
Install as daemon?Yes

Part 5 — Security Configuration

This is the most critical section. Don't skip any of it.

5.1 Configure the Allowlist

nano ~/.openclaw/openclaw.json
{
  "channels": {
    "telegram": {
      "allowFrom": ["YOUR_TELEGRAM_USER_ID_HERE"],
      "groups": {
        "*": { "requireMention": true }
      }
    }
  },
  "gateway": {
    "bind": "tailnet"
  }
}

Replace YOUR_TELEGRAM_USER_ID_HERE with the number from @userinfobot. The bind: tailnet setting means the gateway only listens on your Tailscale interface — never the public internet.

5.2 Secure the Anthropic API Key

echo 'export ANTHROPIC_API_KEY="your-api-key-here"' >> ~/.bashrc
source ~/.bashrc

# OpenClaw automatically reads ANTHROPIC_API_KEY from environment.
# Lock down config file permissions:
chmod 600 ~/.openclaw/openclaw.json

5.3 Set API Spend Limits

In Anthropic Console → Settings → Billing → Usage limits:

  • Set a monthly spend limit of €50
  • Set an email alert at €30 for early warning

Without a spend limit, a misconfigured skill or prompt injection could run up hundreds in API charges in hours.


Part 6 — Docker Isolation

Running OpenClaw in Docker limits what it can access on your server. Strongly recommended if you'll be sending financial documents.

6.1 Create the Project Directory

mkdir ~/openclaw-docker && cd ~/openclaw-docker
mkdir -p workspace receipts

6.2 Create docker-compose.yml

version: '3.8'
services:
  openclaw:
    image: node:22-slim
    container_name: openclaw
    restart: unless-stopped
    working_dir: /home/openclaw
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - HOME=/home/openclaw
    volumes:
      - openclaw_data:/home/openclaw/.openclaw
      - ./workspace:/home/openclaw/workspace
      - ./receipts:/home/openclaw/receipts:ro   # read-only
    network_mode: host   # needed for Tailscale integration
    user: '1000:1000'
    command: >
      sh -c 'npm install -g openclaw@latest && openclaw gateway --port 18789'

volumes:
  openclaw_data:

6.3 Create .env

cat > .env << 'EOF'
ANTHROPIC_API_KEY=your-api-key-here
EOF
chmod 600 .env

6.4 Start OpenClaw

docker compose up -d
docker compose logs -f openclaw
# You should see: 'Gateway listening on port 18789'
# and: 'Telegram channel connected'

Part 7 — Your Four Use Cases

OpenClaw uses two special files to define agent behavior:

  • HEARTBEAT.md — scheduled tasks that run proactively on a cron-like schedule
  • SOUL.md — persistent instructions that shape how the agent behaves

7.1 News Summarization

nano ~/openclaw-docker/workspace/HEARTBEAT.md
## Daily News Briefing

Every morning at 07:30 Berlin time (Europe/Berlin timezone):

1. Search the web for latest news on:
   - AI and machine learning developments
   - Berlin tech startup ecosystem
   - Healthcare technology
   - Fintech and open banking
2. Summarize the 3–5 most significant stories per topic
3. Send as a clean briefing with topic headers to Telegram

You can also install RSS/news skills from clawhub.ai for more targeted sources.

7.2 Stock Price Tracking

Add to HEARTBEAT.md:

## Stock Price Monitor

Every weekday at 09:15 (after Frankfurt market opens):
1. Fetch current prices for: AAPL, NVDA, MSFT, IWDA, VWCE
2. Compare to previous close
3. Flag any moves greater than 2% with context
4. Send a brief summary table to Telegram

Every weekday at 18:00 (after market close):
1. Send end-of-day summary for the same tickers

7.3 Flight Price Monitoring

Add to HEARTBEAT.md:

## Flight Price Monitor

Every Monday and Thursday at 10:00:
1. Check Google Flights for:
   - BER → [DESTINATION] around [DATE_RANGE]
2. Note current cheapest price for each route
3. Alert me if any price has dropped more than €30 since last check
4. Send update to Telegram

Be specific: "BER to CMB, flexible ±3 days around April 15, economy, direct or 1 stop." Vague prompts produce vague results.

7.4 Receipt & Spend Analyzer

This is the most powerful use case — send receipt photos directly to your Telegram bot and the agent logs them automatically.

Set up SOUL.md:

nano ~/openclaw-docker/workspace/SOUL.md
## Spend Tracking

When I send a photo of a receipt:
1. Extract: merchant name, date, total amount, currency
2. Categorize into one of:
   Groceries, Dining, Transport, Health, Clothing,
   Electronics, Entertainment, Utilities, Travel, Other
3. Append to ~/workspace/spending.csv:
   date,merchant,amount,currency,category,notes
4. Confirm: "Added: [Merchant] €[amount] → [Category]"

When I ask for a spend summary:
1. Read spending.csv
2. Show totals by category for the requested period
3. Show top 5 merchants by spend
4. Flag any unusual transactions

Initialize the CSV:

echo 'date,merchant,amount,currency,category,notes' \
  > ~/openclaw-docker/workspace/spending.csv

Usage examples:

→ Send a receipt photo           # auto-categorized and logged
→ "spending this month"          # full breakdown by category
→ "my biggest expenses last week" # ranked list
→ "groceries spending this year"  # filtered analysis

Receipt photos are processed by the Claude API. Anthropic does not train on API data by default — but avoid sending receipts with full card numbers visible.


Part 8 — Testing & Verification

8.1 Test via Telegram

Send these messages to your bot:

Hi
→ Your agent greets you

What's today's date and time?
→ Current date/time with timezone

Search the web for the latest AI news headline
→ A news result (confirms web browsing works)

8.2 Test the Web Dashboard

From any device connected to Tailscale:

http://100.x.x.x:18789

(Replace with your Tailscale IP.) This URL is only reachable from Tailscale devices — never from the public internet.

8.3 Trigger a Manual Heartbeat

# Via Telegram:
Run heartbeat now

# Or via CLI:
docker compose exec openclaw openclaw heartbeat

Part 9 — Maintenance & Backups

9.1 Automated Backups

cat > ~/backup-openclaw.sh << 'EOF'
#!/bin/bash
DATE=$(date +%Y-%m-%d)
BACKUP_DIR=~/backups
mkdir -p $BACKUP_DIR

tar -czf $BACKUP_DIR/openclaw-$DATE.tar.gz \
  ~/.openclaw/ \
  ~/openclaw-docker/workspace/

# Keep only last 14 days
find $BACKUP_DIR -name 'openclaw-*.tar.gz' -mtime +14 -delete
echo "Backup completed: openclaw-$DATE.tar.gz"
EOF

chmod +x ~/backup-openclaw.sh

# Add to crontab (runs daily at 3am)
crontab -e
# Add: 0 3 * * * /home/shahul/backup-openclaw.sh >> /home/shahul/backup.log 2>&1

9.2 Updating OpenClaw

cd ~/openclaw-docker
docker compose down
docker compose pull
docker compose up -d
docker compose logs -f openclaw

9.3 Useful Commands

# View live logs
docker compose -f ~/openclaw-docker/docker-compose.yml logs -f

# Restart / stop
docker compose -f ~/openclaw-docker/docker-compose.yml restart
docker compose -f ~/openclaw-docker/docker-compose.yml down

# Server health
htop
df -h
tailscale status

Part 10 — Cost Summary

ItemEst. Monthly CostNotes
Hetzner CX22€4.15VPS
Hetzner backups€0.8320% of server cost
TailscaleFreePersonal use
Anthropic API€15–40Sonnet 4.6, 4 use cases + daily heartbeats
Total~€20–45Varies with API usage

Key Resources

Security Checklist

  • Telegram allowFrom set to your user ID only
  • Port 18789 not exposed in Hetzner firewall
  • Gateway bound to tailnet interface
  • Anthropic API spend limit set in console
  • ANTHROPIC_API_KEY stored as env var, not in config file
  • openclaw.json and .env have chmod 600 permissions
  • OpenClaw running in Docker with limited volume mounts
  • Daily backups configured via cron
  • Automatic security updates enabled