Meine Heiminfrastruktur mit Claude Code aufgebaut — ein ehrlicher Erfahrungsbericht
In Artikel 1 habe ich geschrieben, dass ich beim Aufbau meiner Infrastruktur gelernt habe, wie man die Fallstricke von Claude Code sicher umgeht. Das war keine leere Ankündigung. Dieser Artikel ist die Einlösung dieses Versprechens.
Was hier entstanden ist: ein vollständig selbst gehosteter Blog-Stack — Ghost als headless CMS, Astro als statischer Frontend-Generator, Gitea Actions als CI/CD-Pipeline, Nginx als Reverse Proxy, Cloudflare als einzige externe Abhängigkeit. Alles läuft auf zwei Raspberry Pis im Heimnetzwerk, abgesichert mit einer Firewall-Architektur die sich vor den meisten Corporate-Umgebungen nicht verstecken muss.
Claude Code war beim Aufbau dabei. Aber nicht als Autopilot — sondern als Assistent, dem ich bei jedem einzelnen Schritt über die Schulter geschaut habe.
Das Setup: Klein, aber ernst gemeint
Bevor wir zu Claude Code kommen, kurz zur Infrastruktur selbst. Denn die ist der Kontext der alles andere bestimmt.
graph TD
Internet([🌐 Internet]) -->|HTTPS| CF[Cloudflare\nZero Trust Tunnel]
CF -->|Verschlüsselt| UCG[UniFi UCG Max\nFirewall / Router]
UCG -->|DMZ VLAN| Pi4
subgraph Heimnetz["🏠 Heimnetzwerk"]
subgraph DMZ["DMZ Zone"]
Pi4[Raspberry Pi 4\nGhost CMS\nNginx\nOllama]
end
subgraph LAN["LAN Zone"]
Pi5[Raspberry Pi 5\nGitea\nNAS / Samba]
end
Pi4 <-->|Intern| Pi5
end
UCG -->|LAN VLAN| Pi5
Dev([💻 MacBook\nEntwicklung]) -->|SSH / lokal| Pi5
Dev -->|SSH / lokal| Pi4
Was hier gebaut wurde:
- Pi 5 (16GB): Gitea als Git-Server und CI/CD-Runner, NAS via Samba, vollständig im LAN — kein direkter Internetzugang
- Pi 4 (4GB): Ghost CMS headless, Nginx als Reverse Proxy, Ollama für lokale KI-Inferenz — in der DMZ, aber nur über Cloudflare erreichbar. Alle Dienste laufen in Docker-Containern.
- UniFi UCG Max: Firewall, Zonenarchitektur (LAN / DMZ / IoT), Firewall-Regeln, Traffic-Monitoring
- Cloudflare Zero Trust Tunnel: Einzige externe Abhängigkeit — aus gutem Grund
Warum Cloudflare die einzige externe Abhängigkeit ist
Kein offener Port im Router. Kein DynDNS. Kein selbst verwaltetes TLS-Zertifikat das abläuft. Der Cloudflare Tunnel baut eine ausgehende Verbindung von meinem Pi zur Cloudflare-Infrastruktur auf — von außen ist kein Port offen, es gibt keine direkte Angriffsfläche.
Das ist eine bewusste Sicherheitsentscheidung, keine Bequemlichkeit. Wer seinen Homeserver mit einem offenen Port 443 betreibt, setzt sich einem anderen Risikoprofil aus als jemand der Zero Trust als Architekturprinzip umsetzt.
Sicherheit die sich vor Corporate-Umgebungen nicht verstecken muss
Ich höre manchmal den Einwand: "Heimlabor ist doch kein ernst zu nehmender Betrieb." Das sehe ich anders.
Was hier implementiert ist:
- Zonenarchitektur (DMZ, LAN, IoT) mit expliziten Firewall-Regeln zwischen den Zonen — kein implizites Vertrauen
- Verschlüsselung auf Kommunikationsebene — TLS für alle externen Verbindungen, SSH für interne
- Verschlüsselung auf Hardwareebene — verschlüsselte Volumes auf den Pis
- Zero Trust Netzwerkzugang via Cloudflare — kein Perimeter-Denken
- Infrastructure as Code — alle Konfigurationen versioniert in Gitea, reproduzierbar
- Automatisierte Deployments mit manuellen Approval Gates — kein Push-to-Production ohne Review
- Vollständiges Traffic-Monitoring via UniFi — jede Verbindung ist sichtbar
Bei zwei Nutzern gibt es eigentlich nur ein Wort zum Thema Performance zu sagen: Genug.
Der Stack: Wie die Teile zusammenspielen
flowchart TD
classDef cloud fill:#1e3a5f,color:#93c5fd,stroke:#93c5fd,stroke-width:1.5px
A[📝 Artikel\nschreiben\nin Ghost] -->|Webhook| B[Gitea\nRepository]
B -->|Trigger| C[Gitea Actions\nCI/CD Pipeline]
C -->|Build| D[Astro\nStatic Site\nGenerator]
D -->|Deploy| E[Dev-Instanz\nzur Prüfung]
E -->|QG1: Code Review| F[👤 Freigabe 1]
F -->|QG2: Visuelle Prüfung| G[👤 Freigabe 2]
G -->|Deploy| H[Nginx Prod\nDocker]
H -->|Cache-Invalidierung| I[Cloudflare\nTunnel]
I -->|HTTPS| J[🌐 Leser]
class F cloud
class G cloud
Ghost läuft als headless CMS in einem Docker-Container — kein Theme, nur die Content API. Artikel werden in Ghost geschrieben und verwaltet, aber das Frontend ist komplett von Ghost getrennt.
Astro mit dem AstroPaper Theme generiert aus den Ghost-Inhalten statische HTML-Seiten. Statisch bedeutet: kein serverseitiges Rendering, kein PHP, keine Datenbank-Anfragen beim Seitenaufruf. Schnell, sicher, wartungsarm.
Gitea Actions übernimmt die CI/CD-Pipeline: Ghost löst per Webhook einen Build aus, Gitea Actions zieht die Inhalte über die Ghost Content API, Astro baut die statische Site. Dabei gibt es zwei Quality Gates — kein Artikel geht ohne explizite Freigabe live.
Claude Code im Einsatz: Was ich wirklich gemacht habe
Jetzt zum eigentlichen Thema. Wie habe ich Claude Code beim Aufbau eingesetzt — und was habe ich dabei gelernt?
Die Grundregel: Nur was ich bewerten kann
Ich habe für mich eine klare Regel aufgestellt: Claude Code kommt nur dort zum Einsatz, wo ich das Ergebnis selbst beurteilen kann. Das klingt selbstverständlich — ist es in der Praxis aber nicht immer. Die Versuchung ist groß, einen generierten YAML-Block einfach zu übernehmen weil er "plausibel aussieht".
Das habe ich bewusst nicht getan. Jeder Schritt wurde freigegeben, nachdem ich verstanden hatte was er tut.
Was Claude Code gut gemacht hat
Gitea Actions Workflows waren ein klarer Stärkebereich. Die YAML-Syntax ist verbose und beim Schreiben fehleranfällig — ein falsches Leerzeichen reicht für einen Fehler. Im Betrieb ist sie dafür sehr stabil und zuverlässig. Claude Code hat mir funktionierende Grundgerüste geliefert die ich dann angepasst und reviewt habe.
# Beispiel: Generiertes Workflow-Grundgerüst für Astro-Build
name: Build and Deploy
on:
repository_dispatch:
types: [ghost-webhook]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Build Astro site
run: npm run build
env:
GHOST_API_URL: ${{ secrets.GHOST_API_URL }}
GHOST_CONTENT_API_KEY: ${{ secrets.GHOST_CONTENT_API_KEY }}
Nginx-Konfigurationen für Reverse Proxy und SSL-Termination — Claude Code hat solide Ausgangspunkte geliefert. Die Cloudflare-spezifischen Header musste ich ergänzen — genau das Szenario das ich in Artikel 1 beschrieben habe: Claude Code kennt meinen Kontext nicht, wenn ich ihn nicht liefere.
Bash-Skripte für Deployment, Backup und Monitoring — hier war Claude Code am zuverlässigsten. Überschaubare Aufgaben, gut definierte Eingaben und Ausgaben, einfach zu reviewen.
Wo ich korrigieren musste
Sicherheitsrelevante Konfigurationen — hier war ich am kritischsten. Claude Code hat mir Nginx-Konfigurationen generiert die technisch korrekt, aber nicht security-hardened waren. Fehlende Security-Header, zu permissive CORS-Einstellungen, Standardwerte die in Produktion nichts zu suchen haben.
Das ist kein Vorwurf an Claude Code. Es ist eine Bestätigung der Kernthese aus Artikel 1: das Modell kennt meinen Sicherheitsanspruch nicht, wenn ich ihn nicht explizit in den Prompt bringe.
Gitea-spezifische Eigenheiten — Gitea Actions ist GitHub Actions sehr ähnlich, aber nicht identisch. Claude Code hat mir mehrfach GitHub-Actions-Syntax generiert die in Gitea nicht funktioniert. Nach dem ersten Mal habe ich das immer explizit im Prompt erwähnt: "Das läuft auf Gitea Actions, nicht GitHub Actions."
Infrastructure as Code Struktur — Claude Code hat funktionierende, aber nicht wartbare Skripte generiert. Zu viele hartcodierte Werte, keine Parametrisierung, keine Fehlerbehandlung. Das habe ich immer nachgebessert — und dabei viel gelernt.
Was ich daraus gelernt habe
Das ist der eigentlich wertvolle Teil. Nicht der generierte Code — sondern was ich durch das kritische Review des generierten Codes gelernt habe.
Wenn ich einen Nginx-Block reviewe den Claude Code generiert hat, muss ich verstehen warum jede Direktive da ist. Das zwingt mich dazu, tiefer in die Dokumentation einzutauchen als ich es ohne KI-Unterstützung vielleicht getan hätte. Claude Code hat mir nicht die Arbeit abgenommen — es hat mir einen Ausgangspunkt gegeben, über den ich nachgedacht habe.
Das ist ein Nutzungsmuster das ich empfehle: Claude Code als Gesprächspartner und Ausgangspunkt, nicht als Autopilot.
Das Ergebnis: Eine Pipeline die funktioniert
Nach einigen Wochen Aufbau, Review-Zyklen und Anpassungen läuft der Stack stabil. Hier der vollständige Deployment-Flow mit beiden Quality Gates:
sequenceDiagram
participant T as Thomas
participant G as Ghost CMS
participant GA as Gitea Actions
participant AS as Astro Build
participant DEV as Dev-Instanz
participant AP1 as Quality Gate 1\nCode Review
participant AP2 as Quality Gate 2\nVisuelle Prüfung
participant PROD as Nginx Prod
participant CF as Cloudflare
T->>G: Artikel veröffentlichen
G->>GA: Webhook auslösen
GA->>AS: Astro Build triggern
AS->>AP1: Build fertig → Code Review
T->>AP1: ✅ Code freigeben
AP1->>DEV: Deploy auf Dev-Instanz
T->>DEV: Visuell prüfen
T->>AP2: ✅ Visuell freigeben
AP2->>PROD: Deploy auf Produktion
PROD->>CF: Cache-Invalidierung via API
Note over CF: Leser sehen neue Version
Zwei Quality Gates — Code Review und visuelle Prüfung auf der Dev-Instanz — bevor etwas produktiv geht. Jeder Pfeil in diesem Diagramm ist ein Schritt den ich verstehe, den ich reviewt habe, und für den ich geradestehen kann. Das war das Ziel.
Fazit: Selbst bauen, selbst verstehen, selbst verantworten
Was ich aus diesem Projekt mitgenommen habe geht über den Tech-Stack hinaus.
Erstens: Ein Heimlabor kann — mit dem richtigen Architekturansatz — eine ernstzunehmende Infrastruktur sein. Zonenarchitektur, Zero Trust, Infrastructure as Code, automatisierte Pipelines mit manuellen Gates — das sind keine Enterprise-Exklusivitäten.
Zweitens: Claude Code ist ein ausgezeichnetes Werkzeug für genau diesen Kontext — wenn man es richtig einsetzt. Als Ausgangspunkt, als Gesprächspartner, als Beschleuniger für Aufgaben die man selbst beurteilen kann. Nicht als Ersatz für das eigene Verständnis.
Drittens: Der Review-Prozess ist nicht der Overhead — er ist der Mehrwert. Ich habe durch das kritische Durcharbeiten von Claude Code-Output mehr über Nginx, Gitea Actions und Bash gelernt als durch passives Lesen von Dokumentation.
Self-hosting ist für mich keine Nostalgie und kein Protest. Es ist eine bewusste Entscheidung für Kontrolle, Verständnis und Souveränität — über meine Daten, meine Infrastruktur, und meinen Tech-Stack.
Dieser Artikel gibt ausschließlich meine persönliche Meinung wieder und steht in keinem Zusammenhang mit beruflichen Tätigkeiten.