Skip to content

About

Fully automated, GitOps-driven single-node home server on k3s, ArgoCD & Tailscale — one Ansible run, zero open ports.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

capulus-core — GitOps Home Lab on k3s, ArgoCD, Tailscale

Ubuntu  k3s  ArgoCD  Tailscale  Cloudflare Tunnel  Ansible

Lizenz  GitOps  Self-hosted  Multi-Cluster


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.



⚡ TL;DR

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

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


Was du bekommst

Schicht Komponente Hinweis
BetriebssystemUbuntu Server 26.04 LTSGehärtet, UFW-Firewall, CrowdSec, NTP-synced, Swap off
Kubernetesk3s (Kanal stable)Drei Cluster: TECH (bare metal), PROD und ENTW (KVM-VMs); Traefik, CoreDNS, local-path, metrics-server
VirtualisierungKVM/libvirtPROD-VM auf dem Homeserver, ENTW-VM auf worker-1, Bridge-Netz direkt im LAN
GitOpsArgoCD + ApplicationSetsEin Hub für TECH + PROD, eine eigene Instanz für ENTW. Ordner unter argocd/apps/<cluster>/ anlegen → mergen → deployed
PromotionGitHub ActionsVersion läuft erst auf ENTW (24 h), dann TECH (2 h), dann PROD — jeweils als PR mit Gesundheits-Gate
IdentitätlldapNutzer im LDAP-Verzeichnis
Split-DNSdnsmasq auf tailscale0*.homeserver aus LAN und Tailnet auflösbar, verteilt auf TECH, PROD und ENTW
WerbeblockingPi-holeFiltert DNS-Anfragen für alle Geräte, die dnsmasq bereits als DNS nutzen — kein Router-Eingriff nötig
Web-AnsibleSemaphore UIEin-Klick-git pull && ansible-playbook gegen das eigene LAN
Monitoring & LogsVictoriaMetrics + Grafana + VictoriaLogsSingle-Node TSDB, vmagent, vmalert, Alertmanager, Hardware-Dashboards, zentrale Logs
Kubernetes-UIHeadlampBrowser-Dashboard für den TECH-Cluster
SecretsSealed Secrets + kubeseal-webguiVerschlüsselte Secrets in Git, je Cluster nur dort entschlüsselbar
Internes TLScert-managerEigene Root-CA, HTTPS auf *.tech/*.prod.homeserver
NotificationsntfySelf-hosted Push — ntfy (iOS + Android)
Live-StreamingMediaMTXRTMP/RTSP-Ingest → HLS-Playback; Publish/Zuschauer per interner mediamtx-Auth (Nutzername/Passwort)
SpeicherUGREEN NAS (NFS)RAID1, StorageClasses nas und immich-nas für alle Cluster, restic-Backup auf USB-Platte
Remote-AccessTailscaleWireGuard-Mesh-VPN — keine Portfreigaben, keine öffentliche IP
Externe ErreichbarkeitCloudflare TunnelJe Cluster ein Tunnel: ausgewählte Dienste öffentlich erreichbar, ohne VPN und ohne offene Ports
CI/CD internArgo Workflows + MinIOPrivate CI/CD-Pipeline + S3-Artifact-Store im Cluster
IngressTraefik (k3s bundled)HTTP/HTTPS-Routing, je Cluster eine eigene Instanz
ProvisioningAnsible (≥ 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.


Quickstart (5 Schritte)

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-core

2. 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-pass

Ergebnis:

ArgoCD UI:  https://argocd.tech.homeserver   (CLI/CI: http://<server-ip>:30080)
Username:   admin
Password:   <auto-generiert>

Drei Cluster

Kartenansicht der Cluster-Standorte
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-vm

Ein Hostname wie n8n.prod.homeserver sagt 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).


Repository-Layout

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)

Monitoring

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; echo

Application hinzufügen (GitOps-Weg)

Erst 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 Application namens my-app im Namespace my-app (PROD-Applications heißen prod-<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.


Service-URLs

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.

Service Tier Cluster URL
Grafana tech TECH https://grafana.tech.homeserver
ArgoCD-Hub – TECH https://argocd.tech.homeserver
ArgoCD ENTW – ENTW http://192.168.178.100:30080
Headlamp tech TECH https://headlamp.tech.homeserver
Semaphore tech TECH https://semaphore.tech.homeserver
lldap (Nutzerverwaltung) tech TECH https://lldap.tech.homeserver
ntfy tech TECH https://ntfy.tech.homeserver
Pi-hole tech TECH https://pihole.tech.homeserver
Argo Workflows tech TECH https://argo-workflows.tech.homeserver
MinIO Console tech TECH https://minio.tech.homeserver
kubeseal-webgui tech TECH https://kubeseal-webgui.tech.homeserver
Vaultwarden tech (Ausnahme) TECH https://vault.tech.homeserver
Zammad tech (Ausnahme) TECH https://zammad.tech.homeserver
Alarmmonitor (alamos-apager) prod TECH https://alamos-apager.prod.homeserver
MediaMTX (Live-Stream-Playback) prod TECH https://stream.prod.homeserver
n8n prod TECH https://n8n.prod.homeserver
Uptime Kuma prod TECH https://uptime-kuma.prod.homeserver
Homeserver-Dashboard-API (carplay-api) prod TECH https://carplay-api.prod.homeserver
pacman (Schulungsobjekt) prod TECH https://pacman.prod.homeserver
Nextcloud prod PROD https://nextcloud.prod.homeserver
Immich prod PROD https://immich.prod.homeserver
Paperless-ngx prod PROD https://paperless.prod.homeserver
Wiki.js prod PROD https://wiki.prod.homeserver
Xibo CMS (xibosignage) prod PROD https://xibo.prod.homeserver
Demo-Apps dev ENTW http://whoami.dev.homeserver, http://demo.dev.homeserver

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.


Networking & Security

PrinzipUmsetzung
Keine öffentlichen PortsZugriff ausschließlich über LAN, Tailscale-VPN oder gezielt per Cloudflare Tunnel (ausgehende Verbindung, kein Port-Forwarding)
Getrennte ClusterTECH, 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-FirewallErlaubt nur SSH, HTTP/HTTPS, k3s-API, ArgoCD-NodePort (HTTPS-only), Flannel, Tailscale-UDP
Opt-in externe ErreichbarkeitNur Dienste mit einem eigenen *-pke-lab.de-Host in ihrer ingress.hosts-Liste sind öffentlich erreichbar, alles andere bleibt intern
Brute-Force-SchutzCrowdSec beobachtet SSH- und Traefik-Logs und lässt einen Firewall-Bouncer auffällige IPs sperren, siehe docs/d-sicherheit/d0020-crowdsec.md
NetworkPoliciesDefault-Deny je Namespace im TECH-Cluster mit expliziten Ausnahmen, siehe docs/d-sicherheit/d0030-network-policies.md
Internes TLScert-manager mit eigener Root-CA (PROD: eigene Intermediate-CA), HTTP wird auf HTTPS umgeleitet, siehe docs/d-sicherheit/d0040-internal-tls.md
SecretsAnsible-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-onlyHat ausschließlich Read-Access auf das Git-Repo
ArgoCD-AppProjectsJe 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ängigkeitenCodeQL 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


Dokumentation

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.

Betriebssystem & Grundlagen (a-betriebssystem/)

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

Kubernetes & GitOps (b-kubernetes-gitops/)

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

Netzwerk & DNS (c-netzwerk-dns/)

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

Sicherheit (d-sicherheit/)

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)

Externe Erreichbarkeit (e-externe-erreichbarkeit/)

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

CI/CD & Automatisierung (f-cicd-automatisierung/)

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

Benachrichtigungen (1-benachrichtigungen/)

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

Betrieb & Hardware (2-betrieb-hardware/)

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.

Apps & Workloads (3-apps-workloads/)

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

Planung (4-planung/)

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

Incidents (5-incidents/)

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

Hintergründe (6-hintergruende/)

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

About

Fully automated, GitOps-driven single-node home server on k3s, ArgoCD & Tailscale — one Ansible run, zero open ports.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages