Skip to content
DE | EN
Go back

Meine Heiminfrastruktur mit Claude Code aufgebaut — ein ehrlicher Erfahrungsbericht

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.

Eine Sache vorab: Diese Infrastruktur ist kein fertiges Produkt — sie ist eine lebendige Struktur. Gleichzeitig mein produktives Setup und meine Experimentier- und Spielwiese. Was heute so aussieht, kann morgen anders sein. Das ist kein Fehler, das ist das Konzept.


Das Projekt im Überblick

Heimlabor-Infrastruktur entsteht nicht über Nacht. Sie wächst in Phasen — jede baut auf der vorherigen auf, jede hat ihren eigenen Lernwert. Hier ist wo wir stehen:

flowchart LR
    P1[✅ Phase 1
Gitea · raspi-5-1] --> P2[✅ Phase 2
Web-Stack · raspi-4-1]
    P2 --> P3[✅ Phase 3
Astro · Design]
    P3 -.-> P4

    P4[✅ Phase 4
CI/CD Pipeline] --> P5[✅ Phase 5
Polish · NAS]
    P5 --> P6[⏳ Phase 6
Authentik · SSO]
    P6 -.-> P7

    P7[⏳ Phase 7
Agentic Core]

    class P1 success
    class P2 success
    class P3 success
    class P4 success
    class P5 success
    class P6 warning
    class P7 warning

Dieser Artikel behandelt Phase 1 bis 4 — von der Gitea-Installation bis zur laufenden CI/CD-Pipeline. Phase 5 (Backup-Skripte, NAS-Integration, Monitoring) ist ebenfalls abgeschlossen, aber Thema eines eigenen Artikels. Was in Phase 6 und 7 geplant ist, gibt es am Ende als Sneak Preview.


Phase 1 & 2: Fundament — Gitea und Web-Stack

Bevor wir zu Claude Code kommen, kurz zur Infrastruktur selbst. Denn die ist der Kontext der alles andere bestimmt.

graph TD
    Internet([🌐 Internet]) --> CF[Cloudflare\nZero Trust Tunnel]
    CF --> UCG[UniFi UCG Max\nFirewall / Router]
    UCG --> Pi4

    subgraph Heimnetz["🏠 Heimnetzwerk"]
        subgraph DMZ["DMZ Zone"]
            Pi4[Raspberry Pi 4-1\nNginx · Astro\nOpenWebUI]
        end
        subgraph LAN["LAN Zone"]
            Pi5[Raspberry Pi 5\nGitea · NAS]
            Pi4b[Raspberry Pi 4-2\nOllama]
        end
        Pi4 <--> Pi5
        Pi5 <--> Pi4b
    end

    UCG --> Pi5
    Dev([💻 MacBook\nEntwicklung]) --> Pi5
    Dev --> Pi4

    class CF cloud

→ Pfeil = Verbindung / Datenfluss → Doppelpfeil = bidirektionale interne Verbindung (LAN) → Cloudflare: einzige externe Abhängigkeit — kein offener Port

Was hier gebaut wurde:

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:

Bei zwei Nutzern gibt es eigentlich nur ein Wort zum Thema Performance zu sagen: Genug.


Phase 3 & 4: Stack und Pipeline

Git ist die einzige Source of Truth. Artikel entstehen als Markdown-Dateien im codecrafter-articles Repo — kein CMS, kein Webhook, keine externe Datenquelle. Was im Repo ist, erscheint auf dem Blog. Was nicht drin ist, nicht.

Die Entscheidung fiel nach einem kurzen Experiment mit Ghost: Zwei Sources of Truth funktionieren nicht. Änderungen in Ghost müssten zurück ins Git, weil Git die Single Source of Truth ist. Also fliegt Ghost raus. Alles raus was keine Miete zahlt.

flowchart LR
    A[📝 Artikel
Markdown in Git] --> B[Gitea
dev-Branch]
    B --> C[Dev-Stage
Astro Build]
    C --> D[👤 Prüfen
Dev-Stage]
    D -.-> E

    E[Pull Request
nach main] --> F[👤 Review
Code Review]
    F --> G[Gitea Actions
Astro Build]
    G --> H[👤 Approval
Manual Gate]
    H -.-> I

    I[Nginx Prod
Docker] --> J[🌐 Leser]

    class F cloud
    class H cloud
    class J success

Git-Branching als Publikations-Workflow: Der dev-Branch ist der Draft-Bereich — Artikel entstehen hier, die Dev-Stage zeigt sie zur Prüfung. Erst ein Pull Request nach main und der erfolgreiche Merge lösen den Produktions-Build aus.

Astro mit dem AstroPaper Theme liest direkt via Content Collections aus dem Repo — statische HTML-Seiten, kein serverseitiges Rendering, keine Datenbank-Anfragen beim Seitenaufruf. Schnell, sicher, wartungsarm.

Gitea Actions übernimmt die CI/CD-Pipeline: Jeder Merge auf main triggert einen Astro-Build. Zwei Quality Gates stehen zwischen Commit und Live-Schaltung — 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 DEV as dev-Branch
    participant DS as Dev-Stage
    participant PR as Pull Request
    participant GA as Gitea Actions
    participant AP as Manual Approval
    participant PROD as Nginx Prod
    participant CF as Cloudflare

    T->>DEV: Artikel committen
    DEV->>DS: Dev-Stage Build
    T->>DS: ✅ Visuell prüfen
    T->>PR: Pull Request nach main
    T->>PR: ✅ Code Review
    PR->>GA: Merge → Build triggern
    GA->>AP: Astro Build fertig
    T->>AP: ✅ Manuell freigeben
    AP->>PROD: Deploy auf Produktion
    PROD->>CF: Cache-Invalidierung via API
    Note over CF: Leser sehen neue Version

Zwei Quality Gates — visuelle Prüfung auf der Dev-Stage und manueller Approval vor dem Produktions-Deploy — bevor etwas live geht. Jeder Schritt ist bewusst, kein Automatismus ersetzt den menschlichen Blick.



Phase 6 & 7: Was als nächstes kommt

Das hier ist Phase 4 — und sie läuft. Was in Teil 2 dieses Artikels behandelt wird, ist noch in Arbeit. Aber es lohnt sich, einen Blick voraus zu werfen.

Authentik — Single Sign-On für alle Services

Ein selbst gehosteter Identity Provider auf Basis von Authentik: OAuth2/OIDC, MFA mit TOTP und WebAuthn. Ein Login für Gitea, Nginx Proxy Manager, OpenWebUI und den Agentic Automation Core. Wer einmal Single Sign-On im Homelab betrieben hat, möchte nicht mehr zurück.

Agentic Automation Core (Phase 7)

Ein LangGraph-basierter Agent für Invoice Processing — vollständig selbst gehostet, mit Human-in-the-Loop als Grundprinzip. LiteLLM als Inferenz-Gateway routet je nach Datenschutz-Anforderung zu Cloud oder lokal. RAG über vergangene Rechnungen, Pydantic-Schema als Quality Gate, NTFY Push-Notification wenn menschliche Entscheidung gefragt ist.

Den Artikel dazu gibt es bereits: Rechnungen per KI verarbeiten — dort ist die Architektur im Detail beschrieben. Wenn Phase 7 live ist, wird dieser Artikel um die echten Erfahrungen erweitert.

Mac Mini als Inferenz-Server

Wahrscheinlich. Apple Silicon mit Unified Memory ist für lokale LLM-Inferenz in einer anderen Liga als ein Raspberry Pi. Nahtlos über LiteLLM eingebunden — kein Code-Änderung am Agent nötig, nur eine neue Route in der Gateway-Konfiguration.

Geplant, noch nicht gebaut. Aber der Platz im Rack ist schon reserviert. 😄

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.


Share this post:

Previous Post
Claude Code: Helpful, But Not a Free Pass
Next Post
Building My Home Infrastructure with Claude Code — An Honest Account