Vollständig automatisierter, GitOps-getriebener Home-Server mit drei getrennten Clustern.
Ansible liefert gehärtete Ubuntu-Hosts, drei schlanke Kubernetes-Cluster (k3s: TECH, PROD, ENTW), Continuous Delivery aus Git (ArgoCD) und Zero-Config-Remote-Access (Tailscale). Neue Versionen laufen erst auf ENTW und wandern nach bestandenem Gesundheits-Gate automatisch als PR nach TECH und PROD.
# 1) Repo klonen
git clone https://github.com/pkr-lab/capulus-core.git && cd capulus-core
# 2) Eigene Details eintragen (Server-IP, Repo-URL, Tailscale-Key)
$EDITOR ansible/inventory/hosts.yml
$EDITOR ansible/group_vars/all.yml
# 3) Collections installieren und Playbook laufen lassen
make install
# oder:
# ansible-galaxy collection install -r ansible/requirements.yml
# ansible-playbook -i ansible/inventory/hosts.yml ansible/site.yml --ask-vault-passAm Ende druckt das Playbook die ArgoCD-URL und das Admin-Passwort. Damit steht der TECH-Cluster mit ArgoCD-Hub. PROD und ENTW kommen als KVM-VMs dazu, siehe Drei Cluster.
| Schicht | Komponente | Hinweis |
|---|---|---|
| Betriebssystem | Ubuntu Server 26.04 LTS | Gehärtet, UFW-Firewall, CrowdSec, NTP-synced, Swap off |
| Kubernetes | k3s (Kanal stable) | Drei Cluster: TECH (bare metal), PROD und ENTW (KVM-VMs); Traefik, CoreDNS, local-path, metrics-server |
| Virtualisierung | KVM/libvirt | PROD-VM auf dem Homeserver, ENTW-VM auf worker-1, Bridge-Netz direkt im LAN |
| GitOps | ArgoCD + ApplicationSets | Ein Hub für TECH + PROD, eine eigene Instanz für ENTW. Ordner unter argocd/apps/<cluster>/ anlegen → mergen → deployed |
| Promotion | GitHub Actions | Version läuft erst auf ENTW (24 h), dann TECH (2 h), dann PROD — jeweils als PR mit Gesundheits-Gate |
| Identität | lldap | Nutzer im LDAP-Verzeichnis |
| Split-DNS | dnsmasq auf tailscale0 | *.homeserver aus LAN und Tailnet auflösbar, verteilt auf TECH, PROD und ENTW |
| Werbeblocking | Pi-hole | Filtert DNS-Anfragen für alle Geräte, die dnsmasq bereits als DNS nutzen — kein Router-Eingriff nötig |
| Web-Ansible | Semaphore UI | Ein-Klick-git pull && ansible-playbook gegen das eigene LAN |
| Monitoring & Logs | VictoriaMetrics + Grafana + VictoriaLogs | Single-Node TSDB, vmagent, vmalert, Alertmanager, Hardware-Dashboards, zentrale Logs |
| Kubernetes-UI | Headlamp | Browser-Dashboard für den TECH-Cluster |
| Secrets | Sealed Secrets + kubeseal-webgui | Verschlüsselte Secrets in Git, je Cluster nur dort entschlüsselbar |
| Internes TLS | cert-manager | Eigene Root-CA, HTTPS auf *.tech/*.prod.homeserver |
| Notifications | ntfy | Self-hosted Push — ntfy (iOS + Android) |
| Live-Streaming | MediaMTX | RTMP/RTSP-Ingest → HLS-Playback; Publish/Zuschauer per interner mediamtx-Auth (Nutzername/Passwort) |
| Speicher | UGREEN NAS (NFS) | RAID1, StorageClasses nas und immich-nas für alle Cluster, restic-Backup auf USB-Platte |
| Remote-Access | Tailscale | WireGuard-Mesh-VPN — keine Portfreigaben, keine öffentliche IP |
| Externe Erreichbarkeit | Cloudflare Tunnel | Je Cluster ein Tunnel: ausgewählte Dienste öffentlich erreichbar, ohne VPN und ohne offene Ports |
| CI/CD intern | Argo Workflows + MinIO | Private CI/CD-Pipeline + S3-Artifact-Store im Cluster |
| Ingress | Traefik (k3s bundled) | HTTP/HTTPS-Routing, je Cluster eine eigene Instanz |
| Provisioning | Ansible (≥ 2.14) | Vollständig idempotent, Role-per-Concern, Vault für Secrets |
Ziel-Hardware (nur TECH): kleine Box mit ≥ 4 GB RAM und ≥ 20 GB Disk. Referenz-Build: HP ProBook 450 G9 (12 vCPU, ~61 GB RAM) als 24/7-Homeserver und Hypervisor, zwei per Wake-on-LAN geweckte Worker (Lenovo M90q, MSI Tower), ein UGREEN NAS. Die Größen der VMs stehen unter Drei Cluster.
Auto-Upgrade-Details
auto_upgrade: true (Default) hält bei jedem Playbook-Run den gesamten Stack aktuell:
| Komponente | Mechanismus |
|---|---|
| APT-Pakete | apt dist-upgrade + unattended-upgrades für tägliche Sicherheits-Patches |
| Tailscale | state: latest für das tailscale-Paket |
| k3s | Folgt k3s_channel (Default stable), pin via k3s_version |
| Helm | Re-Run des offiziellen Installers bei neuem Release |
| ArgoCD | helm upgrade --install ohne --version, pin via argocd_version |
| Reboot | Auto-Reboot wenn APT /var/run/reboot-required setzt (togglebar via auto_reboot_if_required) |
Für reproduzierbare Builds: auto_upgrade: false in ansible/group_vars/all.yml.
Erstmalig auf der Maschine? Start mit Ubuntu-Server-Installation. Komplette Voraussetzungen: docs/a-betriebssystem/a0020-prerequisites.md.
Schritt-für-Schritt aufklappen
1. Repo klonen
git clone https://github.com/pkr-lab/capulus-core.git
cd capulus-core2. Inventory auf den eigenen Server zeigen
$EDITOR ansible/inventory/hosts.yml
# ansible_host (Server-IP) und ggf. ansible_ssh_private_key_file anpassen.3. Variablen setzen
$EDITOR ansible/group_vars/all.yml
# Pflicht: argocd_repo_url, local_subnet, timezone.
# Tailscale-Key muss vault-encrypted sein (nächster Schritt).4. Tailscale-Auth-Key verschlüsseln
ansible-vault encrypt_string 'tskey-auth-DEIN_KEY' --name 'tailscale_auth_key'
# Den !vault-Block in all.yml über den bestehenden tailscale_auth_key-Wert pasten.5. Playbook ausführen
make install
# oder ohne make:
ansible-galaxy collection install -r ansible/requirements.yml
ansible-playbook -i ansible/inventory/hosts.yml ansible/site.yml --ask-vault-passErgebnis:
ArgoCD UI: https://argocd.tech.homeserver (CLI/CI: http://<server-ip>:30080)
Username: admin
Password: <auto-generiert>

Standortübersicht der Cluster-Knoten — wird später um das Standby-HA-Paar mit den Pis erweitert (siehe 40090).
Der Stack besteht seit September 2026 aus drei getrennten k3s-Clustern (Architektur und Begründung, Überblick):
| Cluster | Läuft auf | IP | Für | ArgoCD | Ordner |
|---|---|---|---|---|---|
| TECH | homeserver (bare metal, 24/7) + Worker worker-0/worker-1 |
192.168.178.94 |
Infrastruktur und Betriebsdienste: Identität, Secrets, Monitoring, CI/CD, DNS, Zammad, Vaultwarden, n8n | Hub, verwaltet TECH und PROD | argocd/apps/tech/ |
| PROD | KVM-VM prod-vm auf dem Homeserver (6 vCPU / 24 GiB) |
192.168.178.99 |
Apps mit echtem Nutzerkreis: Nextcloud, Immich, Paperless-ngx, Wiki.js, Xibo | — (vom Hub verwaltet) | argocd/apps/prod/ |
| ENTW | KVM-VM entw-vm auf worker-1 (3 vCPU / 12 GiB) |
192.168.178.100 |
Entwicklung und Tests, absichtlich verwundbare Trainingsumgebung | eigene, isolierte Instanz (Branch entw) |
argocd/apps/entw/ |
Branch entw ──► ArgoCD ENTW ──► ENTW-Cluster
│ (24 h gesund, Smoke-Checks)
▼
Branch main ──► ArgoCD-Hub ──► TECH-Cluster (Promotion-PR, Auto-Merge optional)
│ (2 h gesund)
▼
ArgoCD-Hub ──► PROD-Cluster (Promotion-PR, du bestätigst)
Die Cluster aufbauen (nach make install für TECH):
make worker-0 worker-1 # Worker in den TECH-Cluster aufnehmen
make libvirt-host # KVM + Bridge auf dem Homeserver, legt prod-vm an
make prod # k3s in der prod-vm; danach im Hub registrieren
# (argocd/bootstrap-prod/README.md)
make worker-1-libvirt-host # KVM + Bridge auf worker-1, legt entw-vm an
make entw # k3s + ArgoCD in der entw-vmEin Hostname wie
n8n.prod.homeserversagt nur etwas über das Tier, nicht über den Cluster: welcher Cluster antwortet, entscheidet das DNS (c0040).kubectl-Befehle in den App-Docs gelten für den Cluster, in dem die App läuft (Zugriff je Cluster).
Verzeichnisstruktur anzeigen
capulus-core/
├── README.md
├── Makefile # Convenience-Targets: install, prod, entw, worker-*, lint, render-bootstrap, …
├── IdeasToDeploy.md # Ideensammlung für spätere Apps und Vereins-IT
├── docs/ # Dokumentation, Konventionen: docs/TEMPLATE.md (Kategorien siehe unten)
│ ├── a-betriebssystem/ # Betriebssystem, Architektur-Überblick, Installation
│ ├── b-kubernetes-gitops/ # k3s, ArgoCD, AppProjects, Semaphore, HPA, ENTW-ArgoCD
│ ├── c-netzwerk-dns/ # DNS, Tailscale, WireGuard-Backup, Pi-hole, Ports, Domain-Tiers
│ ├── d-sicherheit/ # Härtung, CrowdSec, NetworkPolicies, TLS, Secrets, lldap
│ ├── e-externe-erreichbarkeit/ # Cloudflare Tunnel
│ ├── f-cicd-automatisierung/ # CI, Promotion ENTW → TECH → PROD, Renovate, Releases, Mirror
│ ├── 1-benachrichtigungen/ # ntfy, Telefon-Alarm
│ ├── 2-betrieb-hardware/ # NAS, Backup, Power-Manager, Drucker, Alerts, Hardware-Monitoring
│ ├── 3-apps-workloads/ # Doku je App
│ ├── 4-planung/ # Pläne und Analysen (teils umgesetzt, siehe Statuszeile im Doc)
│ ├── 5-incidents/ # Vorfallsberichte
│ ├── 6-hintergruende/ # Begründungen, Fallstricke und Vorfall-Regeln zum Code (der Code selbst ist kommentarfrei)
│ ├── superpowers/ # Datierte Plan-/Spec-Docs, eigenes Namensschema
│ └── assets/ # Banner, Cluster-Kartenansicht, Root-CA-Zertifikat
├── renovate.json # Renovate-Konfiguration (siehe docs/f-cicd-automatisierung/f0020-renovate.md)
├── .releaserc.json # semantic-release-Konfiguration (siehe docs/f-cicd-automatisierung/f0030-release-automation.md)
├── .github/
│ ├── dependabot.yml # Dependabot: nur Sicherheits-PRs für Go-Module und Actions (d0080-codeql-dependabot.md)
│ └── workflows/
│ ├── ci.yml # Pflicht-Gate auf PRs: lint, kubeconform, Go, gitleaks (f0070-ci-lint.md)
│ ├── codeql.yml # Code-Scanning: Go, JS, Python, Swift, Workflows (d0080-codeql-dependabot.md)
│ ├── security-issues.yml # täglich: offene CodeQL- und Dependabot-Alerts als Issues (d0080)
│ ├── build-images.yml # Workload-Images bauen (auf PRs ohne Push, f0060-build-images.md)
│ ├── entw-trigger.yml # Push auf entw startet promote-entw.yml sofort
│ ├── promote-entw.yml # entw nach grüner CI als PR an main (f0080-entw-promotion.md)
│ ├── sync-entw.yml # hält entw auf dem Stand von main: PR main → entw mit Auto-Merge (f0080)
│ ├── promote-chain.yml # Versionen ENTW → TECH → PROD nach Gesundheits-Gate (f00b0-promotion-chain.md)
│ ├── release.yml # semantic-release bei jedem Push auf main
│ ├── renovate.yml # Self-hosted Renovate als Fallback (f0020-renovate.md)
│ ├── tailscale-poc.yml # Manueller PoC: Runner im Tailnet (f00a0-tailscale-runner-poc.md)
│ └── mirror-gitlab.yml # Vollspiegelung zu GitLab (f0050-gitlab-mirror.md)
├── scripts/ # Helfer: promote-chain.py, sync-entw.sh, check-doc-links.py, reseal-for-prod.sh, seal-github-token.sh, …
├── ansible/
│ ├── site.yml # Entry-Point TECH-Homeserver (make install)
│ ├── worker-0.yml / worker-1.yml # TECH-Worker (worker-1 ist zusätzlich ENTW-Hypervisor)
│ ├── prod.yml / entw.yml # k3s in der PROD- bzw. ENTW-VM (+ ArgoCD auf ENTW)
│ ├── alarm-kiosks.yml / banana-pi-kiosks.yml / xibo-kiosks.yml # Kiosk-Geräte
│ ├── alert-caller.yml # Telefon-Alarm auf der externen VM (make alert-caller)
│ ├── vaultwarden-restore.yml # Vaultwarden aus dem NAS-Backup wiederherstellen
│ ├── render-bootstrap.yml # rendert argocd/bootstrap/ aus den Templates (make render-bootstrap)
│ ├── requirements.yml # Galaxy-Collections
│ ├── ansible.cfg # Defaults
│ ├── inventory/hosts.yml # Homeserver, Worker, prod-vm, entw-vm, NAS, Kiosks
│ ├── group_vars/ # Alle Knobs (vault-verschlüsselte Secrets)
│ ├── host_vars/ # je Host: homeserver (PROD-VM-Definition), worker-1 (ENTW-VM), prod-vm, entw-vm, …
│ └── roles/ # Role-per-Concern, Übersicht: docs/a-betriebssystem/a0010-overview.md#8-ansible-rollen-und-ihr-wirkungsbereich
│ ├── common/ crowdsec/ dnsmasq/ tailscale/ wireguard_backup/ disable_eee/ # OS, Firewall, DNS, VPN
│ ├── k3s/ k3s_agent/ libvirt_host/ argocd/ # Cluster, VMs, GitOps-Controller
│ ├── semaphore_secrets/ semaphore_targets/ semaphore_bootstrap/ # Semaphore-Web-UI
│ ├── cluster_power_manager/ cluster_power_manager_target/ wake_on_lan/
│ │ nightly_worker_wake/ worker_apt_update/ power_agent/ # Worker per WoL steuern, nächtliches Update
│ ├── thermal_watchdog/ resource_watchdog/ # Selbst-Abschaltung bei Übertemperatur/Dauerlast
│ ├── node_exporter/ smartctl_exporter/ vmagent/ journal_upload/ # Metriken und Logs
│ ├── cups_print_server/ # USB-Drucker per IPP/AirPrint
│ ├── alamos_kiosk/ banana_pi_kiosk/ xibo_kiosk/ # Raspberry-Pi-/Banana-Pi-Kiosks
│ ├── alert_caller/ # Telefon-Alarm: Webhook, Piper-Ansage, baresip-Anruf
│ └── vaultwarden_restore/ # Vaultwarden aus dem NAS-Backup wiederherstellen
├── argocd/
│ ├── promotion.yaml # Konfiguration der Promotion-Kette (Gates, Smoke-Checks), von keinem ApplicationSet gelesen
│ ├── bootstrap/ # TECH-Hub: root-applicationset.yaml + projects.yaml (GENERIERT, make render-bootstrap)
│ ├── bootstrap-prod/ # PROD im Hub: AppProject + zwei ApplicationSets (handgeschrieben), migrations/ (Umzug mit Daten)
│ └── apps/ # Ein Ordner pro ArgoCD-Application, je Cluster
│ ├── tech/ # TECH-Cluster, Projekt "tech" — siehe docs/b-kubernetes-gitops/b0020-argocd-projects.md
│ │ ├── sealed-secrets/ kubeseal-webgui/ cert-manager/ traefik-config/ coredns-custom/ # Secrets, TLS, Ingress/DNS-Konfiguration
│ │ ├── lldap/ # LDAP-Nutzerverzeichnis
│ │ ├── monitoring/ logging/ # VictoriaMetrics + Grafana, VictoriaLogs
│ │ ├── ntfy/ ntfy-bridge/ # Push-Notifications + Alertmanager-Brücke
│ │ ├── alert-caller/ # Telefon-Alarm: Anruf mit Sprachansage (SIP, Piper)
│ │ ├── cloudflared/ pihole/ # Cloudflare Tunnel, DNS-Filter
│ │ ├── nas-storage/ immich-storage/ minio/ # NFS-StorageClasses, S3-Artifact-Store
│ │ ├── argo-workflows/ semaphore/ headlamp/ # CI/CD, Ansible-UI, Kubernetes-Dashboard
│ │ ├── zammad/ vaultwarden/ n8n/ ollama/ # Helpdesk, Passwort-Manager, Automatisierung, lokales LLM
│ │ ├── uptime-kuma/ mediamtx/ pacman/ # Status-Seite, Live-Streaming, Tracking-Demo
│ │ ├── alamos-apager/ alamos-relay/ # Alarmmonitor-Verwaltung, Webhook-Relay
│ │ ├── carplay-api/ github-release-watcher/ # Dashboard-API für die iOS-App (Ordnername historisch), Release-Watcher-CronJob
│ │ └── isc-news-bot/ # News im DLRG ISC per API (Playwright-RPA)
│ ├── prod/ # PROD-Cluster, Projekt "prod" (vom TECH-Hub synchronisiert)
│ │ ├── sealed-secrets/ cert-manager/ traefik-config/ cloudflared/ # eigene Plattform-Grundzutaten des Clusters
│ │ ├── nas-storage/ immich-storage/ # NFS-StorageClasses auch in PROD
│ │ ├── nextcloud/ immich/ paperless-ngx/ # Dateien/Kalender, Fotos, Dokumente
│ │ ├── wikijs/ wiki-docs-sync/ xibosignage/ # Wiki (+ Sync-CronJob), Digital Signage
│ │ └── example-whoami/ demo-app/ # Referenz-Apps
│ └── entw/ # ENTW-Cluster, Projekt "entw" — nur die ENTW-ArgoCD-Instanz liest das (Branch entw), siehe b0050
│ ├── sealed-secrets/ demo-app/ example-whoami/
│ └── README.md
└── ios/ # SwiftUI-App "Homeserver Dashboard" (Backend: carplay-api)
Ein schlanker VictoriaMetrics-+-Grafana-Stack lebt unter argocd/apps/tech/monitoring/ und wird automatisch von ArgoCD ausgerollt. Er überwacht alle drei Cluster, das NAS und die Kiosk-Geräte; Logs laufen zentral in VictoriaLogs (argocd/apps/tech/logging/, Doku).
Stack-Details
| Komponente | Detail |
|---|---|
| TSDB | VMSingle — 15 Tage Retention, 10 Gi local-path-PVC |
| Scrapers | VMAgent scrapet alle VMServiceScrape/VMPodScrape + Prometheus ServiceMonitor-CRDs |
| Host-Metriken | prometheus-node-exporter als DaemonSet auf den TECH-Knoten, node_exporter auf prod-vm/entw-vm, smartctl-Exporter für die Platten |
| Cluster-Metriken | kubelet/cAdvisor, kube-apiserver, kube-state-metrics, CoreDNS |
| Alerts | Default-kube-prometheus-Rules; ntfy-Alertmanager-Bridge |
| Dashboards | Ordner Hardware (Übersicht mit Waben, Server-Detail, Speicher & S.M.A.R.T.), Plattform (TECH) und Anwendungen (TECH), Node Exporter Full, VictoriaMetrics + Kubernetes Views, siehe Hardware-Monitoring |
Grafana öffnen unter https://grafana.tech.homeserver — Admin-Passwort abfragen (auf dem TECH-Cluster):
kubectl -n monitoring get secret grafana-admin \
-o jsonpath='{.data.admin-password}' | base64 -d; echoErst entscheiden, in welchen Cluster die App gehört: ENTW (Entwicklung/Test, der übliche Startpunkt), TECH (Infrastruktur und Betriebsdienste) oder PROD (Apps mit echtem Nutzerkreis). Die Projekte, Ordner und Pflichtschritte je Cluster stehen in docs/b-kubernetes-gitops/b0020-argocd-projects.md.
# Beispiel TECH: Ordner anlegen (Plain-YAML, kustomization.yaml oder Helm-Chart)
mkdir -p argocd/apps/tech/my-app
# my-app in argocd_workloads_apps (oder argocd_platform_apps) ergänzen,
# ansible/roles/argocd/defaults/main.yml — sonst fehlt der AppProject-Namespace, dann:
make render-bootstrap
git checkout -b feat/my-app
git add argocd/apps/tech/my-app/ ansible/roles/argocd/defaults/main.yml argocd/bootstrap/
git commit -m "feat(apps): add my-app"
git push -u origin feat/my-app # PR nach main, main ist geschützt| Cluster | Ordner | Zusätzlich nötig |
|---|---|---|
| TECH | argocd/apps/tech/<app>/ |
Namespace in argocd_platform_apps/argocd_workloads_apps, make render-bootstrap |
| PROD | argocd/apps/prod/<app>/ |
Namespace in argocd/bootstrap-prod/appproject.yaml (im Hub anwenden), bei reinen Manifest-Ordnern Pfad im ApplicationSet, interner Host in dnsmasq_prod_vm_hosts |
| ENTW | argocd/apps/entw/<app>/ auf dem Branch entw |
nichts |
Innerhalb von ~3 Minuten nach dem Merge erkennt ArgoCD das neue Verzeichnis, erstellt eine
Applicationnamensmy-appim Namespacemy-app(PROD-Applications heißenprod-<app>) und synct sie. Details: docs/b-kubernetes-gitops/b0010-argocd.md, docs/b-kubernetes-gitops/b0020-argocd-projects.md, Auslieferung zwischen den Clustern: docs/f-cicd-automatisierung/f00b0-promotion-chain.md.
Jeder Hostname trägt ein Tier-Label (tech = Infrastruktur/Admin, prod = Apps mit echtem Nutzerkreis,
dev = ENTW) — Details und Begründung:
docs/c-netzwerk-dns/c0040-domain-tiers.md. Die Spalte
Cluster zeigt, wo die App tatsächlich läuft; das Tier im Namen ist nur die URL-Konvention.
Zusätzlich zu den internen
*.homeserver-URLs können ausgewählte Dienste über Cloudflare Tunnel öffentlich unter einer eigenen Domain erreichbar gemacht werden (z. B.https://wiki-prod.deine-domain.de— Bindestrich statt Punkt vor dem Tier, siehe docs/c-netzwerk-dns/c0040-domain-tiers.md) — ohne VPN, ohne offene Ports. TECH und PROD haben je einen eigenen Tunnel. Setup: docs/e-externe-erreichbarkeit/e0000-cloudflare-tunnel.md. Welche Dienste aktuell extern erreichbar sind (u. a. Nextcloud, Immich, Wiki.js, Xibo, Vaultwarden, Grafana, ntfy, Status-Seite), steht in der Tabelle unter Externe Erreichbarkeit — bei Immich nötig für Handy-Auto-Backup unterwegs. Der Live-Stream (https://stream-prod.pke-lab.de) ist per mediamtx-eigenem HTTP-Basic-Login abgesichert — kein externer Identity-Provider, kein Cloudflare-Zero-Trust-Konto nötig. Details: docs/3-apps-workloads/30040-mediamtx.md.
| Prinzip | Umsetzung |
|---|---|
| Keine öffentlichen Ports | Zugriff ausschließlich über LAN, Tailscale-VPN oder gezielt per Cloudflare Tunnel (ausgehende Verbindung, kein Port-Forwarding) |
| Getrennte Cluster | TECH, PROD und ENTW haben eigene Pod-/Service-Netze und eigene SealedSecrets-Schlüssel; PROD und ENTW laufen als KVM-VMs, ENTW hat keine Route zu TECH/PROD und keinen ArgoCD-Zugriff vom Hub, siehe 40080 |
| UFW-Firewall | Erlaubt nur SSH, HTTP/HTTPS, k3s-API, ArgoCD-NodePort (HTTPS-only), Flannel, Tailscale-UDP |
| Opt-in externe Erreichbarkeit | Nur Dienste mit einem eigenen *-pke-lab.de-Host in ihrer ingress.hosts-Liste sind öffentlich erreichbar, alles andere bleibt intern |
| Brute-Force-Schutz | CrowdSec beobachtet SSH- und Traefik-Logs und lässt einen Firewall-Bouncer auffällige IPs sperren, siehe docs/d-sicherheit/d0020-crowdsec.md |
| NetworkPolicies | Default-Deny je Namespace im TECH-Cluster mit expliziten Ausnahmen, siehe docs/d-sicherheit/d0030-network-policies.md |
| Internes TLS | cert-manager mit eigener Root-CA (PROD: eigene Intermediate-CA), HTTP wird auf HTTPS umgeleitet, siehe docs/d-sicherheit/d0040-internal-tls.md |
| Secrets | Ansible-Vault für Host-Werte, Sealed Secrets für Cluster-Werte (je Cluster eigener Schlüssel), k3s-Secrets-Encryption at rest + Audit-Log, Rotations-Checkliste in d0060 |
| ArgoCD Read-only | Hat ausschließlich Read-Access auf das Git-Repo |
| ArgoCD-AppProjects | Je Cluster ein Project (tech / prod / entw) begrenzt Quell-Repo und erlaubte Ziel-Namespaces, siehe docs/b-kubernetes-gitops/b0020-argocd-projects.md |
| Code-Scanning & Abhängigkeiten | CodeQL prüft jeden PR (Go, JS, Python, Swift, Workflows), Dependabot öffnet Fix-PRs für verwundbare Abhängigkeiten, offene Funde werden täglich zu Issues, siehe docs/d-sicherheit/d0080-codeql-dependabot.md |
Geschützter main | Änderungen nur per Pull Request mit grüner CI (lint, kubeconform, gitleaks), siehe docs/f-cicd-automatisierung/f0090-branch-schutz-main.md |
Firewall-Ports
| Port | Protokoll | Scope | Zweck |
|---|---|---|---|
| 22 | TCP | LAN + Tailnet | SSH |
| 53 | UDP+TCP | LAN + Tailnet | dnsmasq Split-DNS für *.homeserver |
| 80 | TCP | LAN + Tailnet | Traefik HTTP (leitet auf HTTPS um) |
| 443 | TCP | LAN + Tailnet | Traefik HTTPS |
| 631 | TCP | LAN + Tailnet | CUPS (IPP/AirPrint) |
| 6443 | TCP | LAN + Tailnet | k3s-API |
| 30080 | TCP | LAN + Tailnet | ArgoCD-API/CLI/CI (HTTP, Klartext; die UI läuft per HTTPS über Traefik) |
| 41641 | UDP | Internet | Tailscale-WireGuard |
Die Regeln der common-Rolle gelten auch in prod-vm und entw-vm (dort jeweils mit den eigenen Pod-/Service-CIDRs).
Zusätzlich lässt UFW jeden Verkehr aus dem LAN-Subnetz und dem Tailnet zu, deshalb ist z. B. die ArgoCD-UI der
ENTW-VM (30080, HTTP) aus dem LAN erreichbar. Die vollständige Port-Übersicht je App steht in
docs/c-netzwerk-dns/c0030-port-uebersicht.md.
Vollständige Architektur: docs/a-betriebssystem/a0010-overview.md
Alle Docs liegen unter docs/, sortiert in 12 Kategorie-Unterordner. Jede
Datei trägt eine 5-stellige Hex-ID (erstes Zeichen = Kategorie) — Details
und Konventionen für neue Docs: docs/TEMPLATE.md.
Neu hier? Der beste Einstieg ist der Architektur-Überblick.
| Dokument | Inhalt |
|---|---|
| Ubuntu-Server-Installation | ISO, USB-Stick, Installer, erster Boot |
| Architektur-Überblick | Drei Cluster, Schichten, Traffic-Flows, App-Matrix, Ansible-Rollen |
| Voraussetzungen | Was vor dem Ansible-Run nötig ist |
| Installationsleitfaden | Vollständiger Step-by-Step-Walkthrough |
| Troubleshooting | Diagnose-Playbook für häufige Probleme |
| Dokument | Inhalt |
|---|---|
| k3s-Referenz | Config, kubectl-Cheatsheet, Upgrades |
| ArgoCD-GitOps | Hub und ENTW-Instanz, App-Workflow je Cluster, CLI, Sync-Policies |
| ArgoCD-Projects | Ein Projekt je Cluster (tech/prod/entw), ApplicationSets, neue App hinzufügen |
| Semaphore-UI | Web-UI zum Ausführen von Playbooks |
| Autoskalierung (HPA) | Welche Apps per HorizontalPodAutoscaler mitskalieren, welche bewusst nicht, und mit welchen Schwellenwerten |
| ENTW-ArgoCD | Eigene ArgoCD-Instanz für ENTW, liest nur argocd/apps/entw/; neue App deployen, Rollout, Zugriff |
| Dokument | Inhalt |
|---|---|
| DNS-Architektur | Warum der Home-Server NICHT dein LAN-DNS ist |
| Tailscale-VPN | Auth-Keys, MagicDNS, Subnet-Routes |
| WireGuard-Backup | Notfall-Tunnel für den Fall, dass die Tailscale-Control-Plane ausfällt |
| Pi-hole | Netzwerkweites Werbeblocking als DNS-Filter vor der Fritz!Box — kein Router-Eingriff nötig |
| Port-Übersicht | Interner Service-Port, LAN- und externe Erreichbarkeit für jede App |
| Domain-Tiers | dev/tech/prod-URL-Konvention (app.tier.homeserver), Tier vs. Cluster im DNS, externe Hosts, Cross-App-Referenzen |
| Dokument | Inhalt |
|---|---|
| Incident-Report 12.08.2026 | Postmortem: ApplicationSet-Migration löschte versehentlich 32 Apps, Ursache + Gegenmaßnahmen |
| Security-Härtung — Roadmap | Phasenplan der Security-Härtung nach dem Incident vom 12.08.2026 |
| CrowdSec | Brute-Force-Schutz für SSH und Traefik, Firewall-Bouncer, Whitelist für LAN/Tailnet |
| Cluster-NetworkPolicies | NetworkPolicies je Namespace, Default-Deny + explizite Ausnahmen (Härtung Phase 3) |
| Internes TLS | cert-manager + eigene CA für HTTPS auf *.homeserver, PROD mit eigener Intermediate-CA (Härtung Phase 5) |
| Secrets-Encryption + Audit-Log | k3s Secrets-at-Rest-Verschlüsselung + API-Audit-Log (Härtung Phase 4) |
| Secrets-Rotation-Checkliste | Checkliste zur regelmäßigen Rotation aller Cluster-Secrets (Härtung Phase 7) |
| lldap | Nutzer- und Gruppenverwaltung (LDAP) |
| CodeQL, Dependabot, Security-Issues | Code-Scanning, Fix-PRs für verwundbare Abhängigkeiten, automatische Security-Issues, Vergleich mit Open-Source-Alternativen (Härtung Phase 10) |
| Dokument | Inhalt |
|---|---|
| Cloudflare Tunnel — Setup | Externe Erreichbarkeit ohne VPN: Konzept, zwei Tunnel (TECH/PROD), Tunnel-Einrichtung, Absicherung |
| Cloudflare Tunnel — Deploy | Rollout, neuen Dienst freigeben, Rotation, Troubleshooting |
| Dokument | Inhalt |
|---|---|
| Argo Workflows | Private CI/CD-Pipeline mit MinIO-Artifact-Store |
| Renovate | Automatische Update-PRs für Helm-Chart-Versionen und Image-Tags (Sicherheits-PRs kommen von Dependabot) |
| Release-Automatisierung | GitHub Release + Changelog bei jedem Merge auf main via semantic-release |
| GitHub Release Watcher | Neue GitHub-Releases erkennen und per Zammad-Ticket eine E-Mail-Benachrichtigung auslösen |
| GitLab-Mirror | Vollspiegelung (alle Branches + Tags) zu GitLab als Redundanz für den Fall eines GitHub-Ausfalls |
| Workload-Images bauen | Eigene Workload-Images per GitHub Actions nach GHCR bauen (auf PRs als Probebuild) |
| CI-Pflicht-Gate | make lint, kubeconform (Charts, Manifeste, Bootstrap), Go-Check und gitleaks auf jedem PR |
| ENTW → main Promotion | Neue entw-Commits nach grüner CI als PR an main, main → entw per Sync-Workflow, Rulesets |
Branch-Schutz main |
Ruleset: main nur per Pull Request, vier CI-Jobs als Pflicht-Checks, Admin-Notausgang |
| Tailscale-Runner-PoC | Diagnose: GitHub-Runner erreicht Hub- und ENTW-ArgoCD über Tailscale |
| Promotion-Kette | Versionen ENTW → TECH → PROD als PRs nach bestandenem Gesundheits-Gate (24 h ENTW, 2 h TECH), Smoke-Checks |
| Dokument | Inhalt |
|---|---|
| ntfy iOS-Push | Self-hosted ntfy mit iOS APNs-Relay |
| Telefon-Alarm | Anruf mit deutscher Sprachansage bei schweren Ausfällen (SIP über Linphone, baresip, Piper). Läuft als Pod in TECH, eine externe VM (Ansible-Rolle) ist vorbereitet |
| Dokument | Inhalt |
|---|---|
| NAS-Storage | NFS-StorageClass gegen die UGREEN NAS (RAID1), Migration einzelner Apps von local-path |
| NAS-Backup | Externe USB-Platte am NAS: regelmäßige restic-Backups von volume1 + volume2 |
| Cluster Power Manager | worker-0/worker-1 per Wake-on-LAN je nach Homeserver-Last automatisch dazu- und wieder abschalten |
| Nightly Worker Update | worker-0/worker-1 nachts um 01:00 Uhr per Wake-on-LAN wecken, apt-Update fahren (max. 20 Min.), wieder herunterfahren |
| Drucker (CUPS) | Samsung Xpress M2026 per USB am Homeserver, Freigabe im Heimnetz + Tailnet via IPP/AirPrint |
| GitOps- und Backup-Alerts | Alerts auf ArgoCD-Gesundheit (Degraded, OutOfSync, hängender Sync) und auf CronJobs/Backups ohne Erfolg der letzten 30–36 h |
| Hardware-Monitoring | Grafana-Ordner "Hardware": Waben-Übersicht aller Server/VMs/NAS, Server-Detail (CPU, RAM, Netzwerk, Disk, Temp), Füllstand + S.M.A.R.T. |
Die Spalte Cluster zeigt, wo die App läuft (Ordner unter argocd/apps/).
| Dokument | Cluster | Inhalt |
|---|---|---|
| Zammad | TECH | Helpdesk-/Ticket-System, u. a. Ziel für github-release-watcher-Benachrichtigungen |
| Alarmmonitor-Kiosks | TECH | Raspberry-Pi-Kiosks für ALAMOS AMweb, zentral verwaltet |
| Vereinsheim-Alarmmonitor | TECH | Banana-Pi-Kiosk fürs Vereinsheim, Alarmstatus-Anzeige + Heartbeat-Monitoring |
| Vereinsheim-Windows-PC | — | Windows-PC am Standort: Online-Check und Herunterfahren |
| Wiki.js | PROD | Team-Wiki, docs/ wird per wiki-docs-sync automatisch gespiegelt |
| MediaMTX Live-Streaming | TECH | RTMP/RTSP-Ingest → HLS, Publish- und Zuschauer-Autorisierung über mediamtx' eingebaute interne Benutzerverwaltung (HTTP Basic Auth) |
| Paperless-ngx | PROD | Dokumentenmanagement mit OCR — Briefe, Rechnungen, Verträge scannen und durchsuchen |
| n8n | TECH | Low-Code-Automatisierung — Dienste verknüpfen ohne Programmieren |
| Uptime Kuma | TECH | Status-Seite und Alerting für alle Dienste |
| Rhein-Dashboard | TECH | Grafana: Pegelonline, DWD-Warnungen, ELWIS, Hochwasservorhersage RLP |
| Vaultwarden | TECH | Bitwarden-kompatibler Passwort-Manager für Browser/Mobile-Clients |
| Nextcloud | PROD | Datei-Sync, Kalender, Kontakte |
| Immich | PROD | Foto-/Video-Backup vom Handy inkl. Gesichtserkennung, eigener NAS-Storage-Export |
| Homeserver-Dashboard-API | TECH | Go/Gin-API + power-agent für die reine iOS-App Homeserver Dashboard (Metriken, Alerts, Status, Helligkeit, Wake/Shutdown) |
| xibosignage | PROD | Xibo CMS + Bilder-Slideshow auf Raspberry Pi 3B+, n8n-Workflow für automatisches Einspielen |
| pacman — Besuchertracking | TECH | IP/GeoIP-Besucher-Tracking-Demo für die IT-Security-Schulung |
| Ollama | TECH | Lokales LLM, nur bei Bedarf hochgefahren (vom n8n-Workflow gesteuert) |
| ALAMOS-Einsatzalarm → Zammad | TECH | n8n-Workflow: Einsatzalarm wird zum Zammad-Ticket |
| ALAMOS-Webhook-Relay | TECH | Öffentlicher Mini-Proxy vor n8n, damit ALAMOS den Einsatzalarm-Webhook erreicht, ohne n8n selbst öffentlich zu machen |
| ISC-News-Bot | TECH | News im DLRG ISC per API anlegen (Playwright-RPA), aufgerufen aus n8n, cluster-intern |
| Instagram-Post per Mail | TECH | n8n-Workflow: Mail mit JSON und Bildern wird zum Instagram-Beitrag (Graph API), Bilder kurz über einen einzelnen öffentlichen Pfad für Meta |
| Zentrales Logging | TECH | VictoriaLogs: journald aller Hosts und Pod-Logs an einem Ort |
Pläne und Analysen. Ein Doc trägt in seiner Statuszeile, wie weit es umgesetzt ist.
| Dokument | Inhalt |
|---|---|
| Authelia-SSO | Ursprünglicher SSO-Plan mit Authelia, wieder abgelöst |
| Öffentliches Teilen ohne Gast-Accounts | Immich/Nextcloud: Teilen von Inhalten ohne Gast-Accounts |
| Vereinsheim WoL + Router-VPN | Wake-on-LAN am Standort Vereinsheim, Router-VPN als Fallback |
| GitLab + Proxmox — Prüfung | Analyse: GitLab self-hosted und Proxmox als Hypervisor |
| Zammad-Kalender → Nextcloud | Kalendereinladung aus Zammad über n8n nach Nextcloud und iOS |
| GitHub-Repos versionieren | Versionierung für alle GitHub-Repos |
| Einsatz-Alarm per E-Mail | E-Mail mit den wichtigsten Einsatzdaten |
| Multi-Cluster ENTW/PROD/TECH | Architektur und Umsetzungsplan der Drei-Cluster-Umstellung, Phasen und offene Punkte |
| Dokument | Inhalt |
|---|---|
| NAS-Platte rot, homeserver unerreichbar | Vorfall vom 02.09.2026: Hypothese und Prüfschritte |
| PROD-VM startet nicht mehr, Basis-Image ausgetauscht | Vorfall vom 23.09.2026: Ursache, Behebung und Lehren |
| Pi-hole-Update legt DNS und Tunnel lahm | Vorfall vom 05.10.2026: DNS-Deadlock beim Image-Pull, Notfall-Ablauf und Umstellung auf RollingUpdate |
Warum der Code so gebaut ist: Begründungen, Fallstricke und Vorfall-Regeln. Der Code selbst enthält keine Kommentare, was früher daneben stand, steht hier. Einstieg und Zuordnung von Dateien zu Docs: docs/6-hintergruende/60000-uebersicht.md.
| Dokument | Inhalt |
|---|---|
| Ansible: Hosts, VMs und Playbooks | ENTW-/PROD-VM, libvirt_host (Bridge, dnsmasq-Snippet, Basis-Image), DNS der VMs, Worker-Playbooks, WireGuard-Notzugang |
| Ansible: Rollen | Kiosk-Geräte, Energie-Rollen, Watchdogs, vmagent, journal_upload, Semaphore-Rollen |
| ArgoCD, Bootstrap und SealedSecrets | Bootstrap-Dateien, ignoreDifferences, PROD im Hub, Migrationen, Promotion-Konfiguration, Fallstricke beim Versiegeln |
| Helm-Charts im TECH-Cluster | Gemeinsame Muster, Zertifikate und TLS, Traefik-Metriken, alle TECH-Apps |
| Helm-Charts im PROD-Cluster | PROD-Kopien, Nextcloud, Immich, Wiki.js und wiki-docs-sync, Xibo, Paperless-ngx |
| Monitoring und Alerting | Alertmanager-Routing, VMRules, Scrapes und Labels, Grafana-Ordner, Logging |
| lldap | Chart-Entscheidungen und Secrets |
| carplay-api und iOS-App | Verträge, Absicherung, Datenquellen, Transport über Tailscale |
| pacman (Schulungsobjekt) | Server, Bestenliste, Trainingsmodus, Frontend-Skripte |
| CI-Workflows, Skripte und Lint | Workflows, Promotions- und Sync-Skripte, Ruleset, Dependabot/Renovate, Lint-Konfiguration |
Weitere Ordner-READMEs: argocd/apps/entw/ (ENTW-Ordner), argocd/bootstrap-prod/ (PROD im Hub anbinden, Umzug mit Daten), argocd/apps/tech/pacman/, argocd/apps/tech/carplay-api/, ios/ (iOS-App).
MIT — siehe LICENSE · Made with ☕ & GitOps