⬡ Open Source · $0/Monat · Gehärtet

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.

Gateway
Gehärteter Container
LLM
Gemini 2.5 Flash
Kanal
Telegram Bot
Website
Eigene Subdomain
Bilder
Pollinations.ai
Kosten
$0/Monat

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

bash
# 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

  1. Gehe zu https://aistudio.google.com/apikey
  2. Mit Google-Account einloggen
  3. "Create API Key" klicken
  4. Key in die .env eintragen

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).

yaml · docker-compose.yml
# 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
Anpassen: 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.

bash · firewall-rules.sh
#!/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

ini · openclaw-firewall.service
[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
bash
systemctl daemon-reload
systemctl enable openclaw-firewall.service
/opt/openclaw/firewall-rules.sh

Phase 4Starten und Konfigurieren

bash
# 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

bash
# 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

  1. Öffne Telegram → suche @BotFather
  2. Sende /newbot
  3. Vergib Namen und Username
  4. Kopiere das Bot-Token

Bot in OpenClaw eintragen

bash
docker exec openclaw-gateway \
  node dist/index.js channels add --channel telegram --token "DEIN-BOT-TOKEN"

docker compose restart openclaw-gateway

Device-Pairing

  1. Schicke dem Bot eine Nachricht in Telegram
  2. Du bekommst einen Pairing-Code zurück
  3. Bestätige:
bash
docker exec openclaw-gateway \
  node dist/index.js pairing approve telegram DEIN-PAIRING-CODE

Phase 6Bildgenerierung (optional)

Kostenlos über Pollinations.ai — kein API-Key, kein Limit. Erstelle einen Skill, den OpenClaw automatisch nutzt.

bash
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:

markdown · SKILL.md
---
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)

bash
# 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-web

OpenClaw 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.

DateiEmpfehlung
BOOTSTRAP.mdLöschen nach dem ersten Setup
AGENTS.mdRadikal kürzen — irrelevante Abschnitte entfernen
USER.mdAusfüllen oder löschen — leere Templates kosten Tokens
HEARTBEAT.mdLöschen wenn Heartbeat nicht genutzt wird
SOUL.mdMeta-Kommentare und tote Links entfernen
Ergebnis: Context von ~4.500 auf ~1.800 Tokens pro Nachricht reduzierbar. Das verdoppelt die Anzahl möglicher Nachrichten im Free Tier.

Sicherheitscheckliste

  • read_only: true + tmpfs für /tmp, /run
  • cap_drop: ALL — keine Linux Capabilities
  • no-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)
  • .env mit chmod 600
  • Firewall-Regeln persistent (systemd)
  • Nginx mountet Workspace read-only
  • Gateway und Webserver auf getrennten Netzwerken
  • Kein Docker-Gruppe User

Architektur

Internet ──▶ Traefik ──▶ Nginx (read-only) ◀── Volume ──▶ OpenClaw (isoliert) HTTPS │ proxy-Netzwerk openclaw-isolated │ │ ╳ kein Weg zwischen den Netzwerken ──────────╳ │ iptables: DROP auf 10.0.0.0/16 172.16.0.0/12, 192.168.0.0/16 169.254.169.254, 224.0.0.0/4NUR Internet erlaubt (Gemini API, Pollinations)
  • 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

bash
# 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:

ProviderEnv-VariableModell-IDKosten
Google GeminiGOOGLE_API_KEYgoogle/gemini-2.5-flashKostenlos (250 Req/Tag)
MistralMISTRAL_API_KEYmistral/mistral-large-latestKostenlos (Experiment)
AnthropicANTHROPIC_API_KEYanthropic/claude-haiku-4-5-20251001~$5-9/Monat
OpenAIOPENAI_API_KEYopenai/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.mode auf "off".

Ressourcenverbrauch

KomponenteRAMDiskCPU (idle)
OpenClaw Gateway~520 MB3,15 GB (Image) + ~3 MB<0,1%
Nginx Webserver~3 MB62 MB (Image)0%
Total~525 MB~3,2 GB~0,1%