Gehärtete OpenClaw Installation auf einem Hetzner VPS
Sichere, kostenlose Installation von OpenClaw als persönlicher KI-Assistent. Inklusive Netzwerk-Isolation, Telegram-Integration, eigenem Webserver und Bildgenerierung — ohne GPU, ohne laufende API-Kosten.
Voraussetzungen
- VPS mit mindestens 4 GB RAM und 10 GB freiem Speicher (z.B. Hetzner CX33)
- Ubuntu 24.04 LTS
- Docker und Docker Compose installiert
- SSH-Zugang
- Ein Google AI Studio API-Key (kostenlos, keine Kreditkarte)
- Ein Telegram-Bot-Token (via @BotFather)
Phase 1Verzeichnisstruktur und Secrets
# Verzeichnisse anlegen mkdir -p /opt/openclaw/{config,workspace/public,logs} chmod 700 /opt/openclaw # Gateway-Token generieren GATEWAY_TOKEN=$(openssl rand -hex 32) # .env erstellen cat > /opt/openclaw/.env << EOF # LLM Provider — Google Gemini (kostenlos) GOOGLE_API_KEY=DEIN_GOOGLE_API_KEY # Gateway-Sicherheit OPENCLAW_GATEWAY_TOKEN=${GATEWAY_TOKEN} # Bind-Modus OPENCLAW_BIND_MODE=loopback # Node Environment NODE_ENV=production EOF chmod 600 /opt/openclaw/.env
Google API-Key erstellen
- Gehe zu https://aistudio.google.com/apikey
- Mit Google-Account einloggen
- "Create API Key" klicken
- Key in die
.enveintragen
Phase 2Docker Compose
Die Compose-Datei enthält zwei Services: den OpenClaw Gateway (isoliert) und einen optionalen Nginx Webserver (für statische Seiten über eine Subdomain).
# OpenClaw — Gehärtete Installation services: openclaw-gateway: image: ghcr.io/openclaw/openclaw:2026.4.11 container_name: openclaw-gateway restart: unless-stopped hostname: openclaw # --- Sicherheit --- security_opt: - no-new-privileges:true cap_drop: - ALL read_only: true tmpfs: - /tmp:noexec,nosuid,size=100M - /run:noexec,nosuid,size=10M - /home/node/.npm:noexec,nosuid,size=50M # --- Netzwerk: NUR Loopback --- ports: - "127.0.0.1:18789:18789" # --- Volumes --- volumes: - /opt/openclaw/config:/home/node/.openclaw:rw - /opt/openclaw/workspace:/home/node/workspace:rw env_file: - /opt/openclaw/.env environment: - NODE_ENV=production - OPENCLAW_BIND_MODE=loopback # --- Ressourcen-Limits --- deploy: resources: limits: memory: 1G cpus: '1.0' reservations: memory: 256M cpus: '0.25' # --- Health-Check --- healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:18789/health').then(r=>{if(!r.ok)throw 1})"] interval: 30s timeout: 10s retries: 3 start_period: 30s networks: - openclaw-isolated logging: driver: json-file options: max-size: "20m" max-file: "3" # --- DNS: Nur öffentliche Resolver --- dns: - 1.1.1.1 - 8.8.8.8 # --- Static Webserver (optional) --- openclaw-web: image: nginx:alpine container_name: openclaw-web restart: unless-stopped security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - NET_BIND_SERVICE - CHOWN - SETUID - SETGID read_only: true tmpfs: - /tmp:noexec,nosuid,size=10M - /var/cache/nginx:noexec,nosuid,size=20M - /run:noexec,nosuid,size=5M # READ-ONLY Mount volumes: - /opt/openclaw/workspace/public:/usr/share/nginx/html:ro deploy: resources: limits: memory: 128M cpus: '0.25' networks: - proxy # Anpassen: z.B. "coolify", "traefik_default" labels: - "traefik.enable=true" - "traefik.http.routers.https-openclaw-web.rule=Host(`SUBDOMAIN.example.com`)" - "traefik.http.routers.https-openclaw-web.tls=true" - "traefik.http.routers.https-openclaw-web.tls.certresolver=letsencrypt" - "traefik.http.services.https-openclaw-web.loadbalancer.server.port=80" networks: openclaw-isolated: driver: bridge driver_opts: com.docker.network.bridge.name: br-openclaw ipam: config: - subnet: 10.0.200.0/24 proxy: external: true
SUBDOMAIN.example.com durch die eigene Domain ersetzen. proxy Netzwerk-Name an das Setup anpassen. Ohne Webserver den gesamten openclaw-web Service entfernen.Phase 3Netzwerk-Isolation
OpenClaw darf nur ins öffentliche Internet (für API-Calls), nicht zu anderen Docker-Containern. Die Regeln nutzen Docker's DOCKER-USER Chain — den offiziellen Mechanismus für Custom-Firewallregeln.
#!/bin/bash # OpenClaw Netzwerk-Isolation via DOCKER-USER Chain set -euo pipefail OPENCLAW_SUBNET="10.0.200.0/24" CHAIN="DOCKER-USER" # Alte Regeln entfernen (idempotent) for TARGET in DROP RETURN; do while iptables -D "$CHAIN" -s "$OPENCLAW_SUBNET" -j "$TARGET" 2>/dev/null; do :; done done for DEST in 10.0.0.0/16 172.16.0.0/12 192.168.0.0/16 169.254.169.254/32 224.0.0.0/4; do while iptables -D "$CHAIN" -s "$OPENCLAW_SUBNET" -d "$DEST" -j DROP 2>/dev/null; do :; done done # Regeln setzen iptables -I "$CHAIN" 1 -s "$OPENCLAW_SUBNET" -d "$OPENCLAW_SUBNET" -j RETURN iptables -I "$CHAIN" 2 -s "$OPENCLAW_SUBNET" -d 10.0.0.0/16 -j DROP iptables -I "$CHAIN" 3 -s "$OPENCLAW_SUBNET" -d 172.16.0.0/12 -j DROP iptables -I "$CHAIN" 4 -s "$OPENCLAW_SUBNET" -d 192.168.0.0/16 -j DROP iptables -I "$CHAIN" 5 -s "$OPENCLAW_SUBNET" -d 169.254.169.254/32 -j DROP iptables -I "$CHAIN" 6 -s "$OPENCLAW_SUBNET" -d 224.0.0.0/4 -j DROP
Persistent via systemd
[Unit] Description=OpenClaw Network Isolation Firewall Rules After=docker.service Requires=docker.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/opt/openclaw/firewall-rules.sh [Install] WantedBy=multi-user.target
systemctl daemon-reload systemctl enable openclaw-firewall.service /opt/openclaw/firewall-rules.sh
Phase 4Starten und Konfigurieren
# Container starten cd /opt/openclaw docker compose up -d openclaw-gateway # Warten, dann Ownership fixen sleep 15 chown -R 1000:1000 /opt/openclaw/config /opt/openclaw/workspace # Neustart mit korrekten Permissions docker compose restart openclaw-gateway
Modell und Plugins konfigurieren
# Gemini 2.5 Flash als Modell docker exec openclaw-gateway \ node dist/index.js config set agents.defaults.model.primary "google/gemini-2.5-flash" # Unnötige Plugins deaktivieren (spart RAM + schnellerer Start) docker exec openclaw-gateway \ node dist/index.js config set plugins.entries.acpx.enabled false docker exec openclaw-gateway \ node dist/index.js config set plugins.entries.browser.enabled false # Active Memory aktivieren (kostenlos auf Gemini) docker exec openclaw-gateway \ node dist/index.js config set plugins.entries.active-memory.enabled true # Neustart docker compose restart openclaw-gateway
Phase 5Telegram-Bot einrichten
Bot erstellen
- Öffne Telegram → suche @BotFather
- Sende
/newbot - Vergib Namen und Username
- Kopiere das Bot-Token
Bot in OpenClaw eintragen
docker exec openclaw-gateway \ node dist/index.js channels add --channel telegram --token "DEIN-BOT-TOKEN" docker compose restart openclaw-gateway
Device-Pairing
- Schicke dem Bot eine Nachricht in Telegram
- Du bekommst einen Pairing-Code zurück
- Bestätige:
docker exec openclaw-gateway \
node dist/index.js pairing approve telegram DEIN-PAIRING-CODEPhase 6Bildgenerierung (optional)
Kostenlos über Pollinations.ai — kein API-Key, kein Limit. Erstelle einen Skill, den OpenClaw automatisch nutzt.
mkdir -p /opt/openclaw/config/workspace/skills/imagine chown -R 1000:1000 /opt/openclaw/config/workspace/skills
Erstelle skills/imagine/SKILL.md mit folgendem Inhalt:
---
name: imagine
description: "Generate images via Pollinations.ai (free, no API key)."
metadata:
{ "openclaw": { "emoji": "🎨", "requires": { "bins": ["curl"] } } }
---
# Imagine — Bildgenerierung
```bash
curl -sL "https://image.pollinations.ai/prompt/PROMPT?width=1024&height=1024&nologo=true" \
-o /home/node/workspace/public/bild.jpg
```
Parameter: width, height, nologo=true, model (flux, flux-realism, flux-anime)Phase 7Webserver starten (optional)
# Platzhalter-Seite
cat > /opt/openclaw/workspace/public/index.html << 'HTML'
<!DOCTYPE html>
<html><body><h1>OpenClaw Workspace</h1></body></html>
HTML
chown 1000:1000 /opt/openclaw/workspace/public/index.html
docker compose up -d openclaw-webOpenClaw schreibt Dateien nach /home/node/workspace/public/ und sie sind sofort über die Subdomain erreichbar.
Phase 8Context optimieren
OpenClaw schickt bei jeder Nachricht mehrere Workspace-Dateien als Context an das LLM. Jedes Token zählt gegen das Tageslimit.
| Datei | Empfehlung |
|---|---|
BOOTSTRAP.md | Löschen nach dem ersten Setup |
AGENTS.md | Radikal kürzen — irrelevante Abschnitte entfernen |
USER.md | Ausfüllen oder löschen — leere Templates kosten Tokens |
HEARTBEAT.md | Löschen wenn Heartbeat nicht genutzt wird |
SOUL.md | Meta-Kommentare und tote Links entfernen |
Sicherheitscheckliste
read_only: true+ tmpfs für /tmp, /runcap_drop: ALL— keine Linux Capabilitiesno-new-privileges— kein setuid/setgid- Loopback-Binding (
127.0.0.1:18789) - iptables blockieren Docker-Netzwerke
- iptables blockieren private IP-Bereiche
- iptables blockieren Cloud-Metadata
- DNS nur 1.1.1.1 + 8.8.8.8
- Ressourcen-Limits (1 GB RAM, 1 CPU)
- Gepinnte Image-Version (kein
latest) .envmit chmod 600- Firewall-Regeln persistent (systemd)
- Nginx mountet Workspace read-only
- Gateway und Webserver auf getrennten Netzwerken
- Kein Docker-Gruppe User
Architektur
- OpenClaw kann nur ins öffentliche Internet (API-Calls)
- Nginx kann nur statische Dateien ausliefern (read-only)
- Beide teilen nur ein Volume, keine Netzwerkverbindung
- Ein Angreifer müsste beide Container gleichzeitig kompromittieren
Nützliche Befehle
# Status docker ps --filter name=openclaw --format "table {{.Names}}\t{{.Status}}" # Logs docker logs -f openclaw-gateway # Config anzeigen docker exec openclaw-gateway node -e " const fs = require('fs'); const c = JSON.parse(fs.readFileSync('/home/node/.openclaw/openclaw.json','utf8')); console.log(JSON.stringify(c, null, 2));" # Modell wechseln docker exec openclaw-gateway \ node dist/index.js config set agents.defaults.model.primary "google/gemini-2.5-flash" docker compose restart openclaw-gateway # Streaming an/aus docker exec openclaw-gateway \ node dist/index.js config set channels.telegram.streaming.mode "partial" # Update (Version in docker-compose.yml anpassen) docker compose pull openclaw-gateway docker compose up -d openclaw-gateway docker image prune -f # Ressourcen docker stats --no-stream openclaw-gateway openclaw-web
Alternative LLM-Provider
Einfach .env und Modell-Config anpassen:
| Provider | Env-Variable | Modell-ID | Kosten |
|---|---|---|---|
| Google Gemini | GOOGLE_API_KEY | google/gemini-2.5-flash | Kostenlos (250 Req/Tag) |
| Mistral | MISTRAL_API_KEY | mistral/mistral-large-latest | Kostenlos (Experiment) |
| Anthropic | ANTHROPIC_API_KEY | anthropic/claude-haiku-4-5-20251001 | ~$5-9/Monat |
| OpenAI | OPENAI_API_KEY | openai/gpt-5.4-mini | ~$3-8/Monat |
Bekannte Einschränkungen
- Bonjour/mDNS verursacht ~90 Sekunden Startup-Delay. Kein Fix verfügbar, nur bei Restarts relevant.
- acpx Plugin (Code-Ausführung) funktioniert nicht mit
read_only+noexec— deaktivieren. - Browser Plugin braucht ~200-500 MB RAM — auf kleinen Servern deaktivieren.
- Gemini Bildgenerierung in Deutschland nicht verfügbar — Pollinations.ai als Alternative.
- Streaming kann je nach Version JSON-Parse-Fehler verursachen. Fix:
streaming.modeauf"off".
Ressourcenverbrauch
| Komponente | RAM | Disk | CPU (idle) |
|---|---|---|---|
| OpenClaw Gateway | ~520 MB | 3,15 GB (Image) + ~3 MB | <0,1% |
| Nginx Webserver | ~3 MB | 62 MB (Image) | 0% |
| Total | ~525 MB | ~3,2 GB | ~0,1% |