Claude mit dem Homelab verbinden: MCP-Connectors und wie ich sie absichere
Seit ein paar Wochen kann Claude bei mir Container auf Proxmox anschauen, meinen Kalender lesen, im UniFi-Netzwerk nachsehen und Dokumente in Paperless finden. Möglich machen das MCP-Server (Model Context Protocol). Jeder davon ist ein kleiner Dienst, der eine API so verpackt, dass ein KI-Assistent sie als Tool benutzen kann. Das ist praktisch, aber ein MCP-Server mit Proxmox-Zugang ist im Grunde ein Admin-Login mit HTTP-Schnittstelle. Deshalb geht es in diesem Artikel vor allem darum, wie ich die Dinger absichere.
Welche MCP-Server bei mir laufen
- Proxmox, um VMs und Container zu verwalten
- iCloud-Kalender über CalDAV mit
caldav-mcp. Der Server spricht von Haus aus nur stdio, mitsupergatewaydavor ist er per HTTP erreichbar. - UniFi Network für beide Standorte mit
sirkirby/unifi-network-mcp. Der Permission-Mode steht auf „confirm“, Änderungen muss ich also bestätigen. Das Löschen von Policies ist komplett abgeschaltet. - WHOOP für meine Fitnessdaten
- Paperless für meine Dokumente

Ein LXC pro MCP-Server
Jeder MCP-Server bekommt bei mir einen eigenen kleinen, unprivilegierten LXC auf Proxmox, darin läuft Docker. Das ist etwas mehr Overhead, dafür liegen die Credentials pro Dienst getrennt. Wenn der Kalender-Container kompromittiert wäre, steht dort kein Proxmox-Token und kein UniFi-Passwort drin.
Interner Zugriff: Caddy mit Bearer Token
Für Claude Code auf meinem Rechner reicht interner Zugriff. Die MCP-Server hängen hinter meinem Caddy und sind nur aus dem LAN oder über Tailscale erreichbar. Zusätzlich prüft Caddy einen Bearer Token. Fehlt der Authorization-Header oder stimmt er nicht, gibt es 401:
mcp-proxmox.int.example.de {
@extern not remote_ip 192.168.1.0/24 100.64.0.0/10
respond @extern 403
@noauth not header Authorization "Bearer DEIN-LANGER-TOKEN"
respond @noauth 401
reverse_proxy 192.168.1.50:3000
}
100.64.0.0/10 ist der Adressbereich von Tailscale, das LAN-Subnetz musst du an dein Netz anpassen.
Firewall im LXC: nur Caddy darf rein
Der Token in Caddy hilft nichts, wenn jemand im LAN direkt auf den Port des Containers geht. Deshalb blockiert eine iptables-Regel im LXC alles, was nicht von der IP des Caddy-Containers kommt. Docker-Ports umgehen die normale INPUT-Chain, die Regel gehört daher in die Chain DOCKER-USER:
iptables -I DOCKER-USER -i eth0 -p tcp -m multiport --dports 3000,8080 ! -s <caddy-ip> -j DROP
Das -i eth0 hat mich einen Abend gekostet. Ohne die Angabe hat die Regel auch den Traffic zwischen den Containern innerhalb von Docker gedroppt. Caddy bekam dann 502 mit „i/o timeout“, obwohl der MCP-Server lief. Mit -i eth0 greift die Regel nur für Pakete, die von außen in den LXC kommen.
Öffentliche Connectors für die Claude-App
Damit ich Kalender und WHOOP auch in der Claude-App am Phone oder im Browser nutzen kann, müssen diese Server aus dem Internet erreichbar sein. Die Requests kommen dann von Anthropics Servern. Davor sitzen zwei Schichten:
- OAuth 2.1. Für den Kalender übernimmt das
mcp-auth-proxy, der WHOOP-Server hat OAuth schon eingebaut. - Ein IP-Filter in Caddy: Requests auf
/mcpkommen nur aus dem ausgehenden IP-Bereich durch, den Anthropic auf seiner Doku-Seite zu IP-Adressen veröffentlicht (160.79.104.0/21). Die Login-Seiten bleiben öffentlich, sind aber passwortgeschützt, weil ich mich ja selbst im Browser anmelden muss.
kalender.example.de {
@blocked {
path /mcp*
not remote_ip 160.79.104.0/21
}
respond @blocked 403
reverse_proxy 192.168.1.51:8080
}
Schau vor dem Übernehmen auf Anthropics Seite nach, ob der Bereich noch aktuell ist.

Wie schnell das Internet neue Hostnamen findet, hat mich trotzdem überrascht. Wenige Minuten nachdem die Zertifikate ausgestellt waren, tauchten die ersten Scanner in den Logs auf. Seitdem läuft bei mir CrowdSec, dazu gibt es einen eigenen Artikel.
Credentials kommen nie in den Chat
Beim Einrichten ist es verlockend, Claude einfach den API-Key zu geben, damit es die Config schreibt. Mache ich nicht. Stattdessen liegt in jedem Container ein kleines Script, das ich selbst in der Shell starte. Es fragt jeden Wert einzeln ab, fragt bei leeren Pflichtfeldern noch mal nach, schneidet Leerzeichen ab und prüft die Länge. Wo es geht, testet es den Wert direkt gegen die API. Am Ende gibt es nur die Längen der Werte aus, nie die Werte selbst. So kann ich Claude die Ausgabe zeigen, ohne dass ein Secret im Verlauf landet.
ask() {
local val=""
while [ -z "$val" ]; do
read -rsp "$1: " val; echo >&2
val="${val#"${val%%[![:space:]]*}"}"
val="${val%"${val##*[![:space:]]}"}"
done
printf '%s' "$val"
}
TOKEN="$(ask 'API Token')"
echo "API Token: ${#TOKEN} Zeichen"
Was sonst noch schiefging
Caddyfile auf 600 gesetzt, Reload kaputt
Weil im Caddyfile jetzt Tokens stehen, habe ich es auf root-only gesetzt (600). Danach scheiterte der Reload, denn Caddy läuft als eigener User und konnte die Datei nicht mehr lesen. Richtig ist Owner root, Gruppe caddy, Rechte 640:
chown root:caddy /etc/caddy/Caddyfile
chmod 640 /etc/caddy/Caddyfile
systemctl reload caddy
Der erste Kalender-Server ist abgestürzt
Angefangen habe ich mit dav-mcp. Der wollte auf der CalDAV-URL auch CardDAV sprechen und ist dabei gecrasht. Bei iCloud liegen die Kontakte auf einem anderen Host als die Kalender, das konnte also nicht klappen. Mit caldav-mcp läuft es stabil.
iCloud und Advanced Data Protection
Für CalDAV brauchst du bei iCloud ein app-spezifisches Passwort, dein normales Apple-Passwort funktioniert nicht. Ich habe Advanced Data Protection aktiv. Die CalDAV-Kalender funktionieren damit weiterhin, die iCloud-Erinnerungen dagegen sind über diesen Weg nicht erreichbar.
Hast du Claude oder einen anderen Assistenten schon an dein Homelab angebunden? Schreib in die Kommentare, wie du es absicherst.