
🌐 Auch auf: English · Français · Español
In ein paar meiner letzten Beiträge hatte ich erwähnt, dass ich nach einem Weg suche, meinen Homelab-Automatisierungscode zu veröffentlichen, *ohne aus Versehen gleich meine komplette Infrastruktur mit zu open-sourcen* 😅
Das ist überraschend knifflig, wenn dein Ansible-Inventory aussieht wie eine Cyberpunk-Schatztruhe voller Vaults, Secrets und hostspezifischer Variablen. 🔐🐉
Nach etwas Trial and Error, Koffein und fragwürdigen Lebensentscheidungen… habe ich endlich ein Setup gefunden, das wunderbar funktioniert:
👉 zwei getrennte Git-Remotes.
Eine **private, selbst gehostete Gitea-Instanz** enthält das *echte* Repository – inklusive verschlüsselter Secrets, Vault-Dateien und aller pikanten Interna.
Ein **öffentliches GitHub-Repo** bekommt dagegen nur den sauberen Automatisierungscode; sensible Dateien sind per `.gitignore` ausgeschlossen und durch freundliche `.example`-Vorlagen ersetzt. 🧼✨
Alles Geheime ist ohnehin mit **Ansible Vault (AES-256)** verschlüsselt – selbst wenn also doch mal etwas durchrutscht, bekommt ein Angreifer nur verschlüsseltes Kauderwelsch. 🧠💾
📦 Repo:
👉 github.com/aptupgrademe/www_k3s
Das Projekt richtet wahlweise **Nextcloud** oder **WordPress** auf einem frischen **Single-Node-K3s-Cluster** unter **AlmaLinux 9** ein.
Ein Befehl.
Null Klickerei.
Maximale Nerd-Energie. ⚡🤓
🧠 Die Idee
Führe Folgendes aus:
ansible-playbook blog.yml --limit <host> --ask-vault-pass…gegen einen komplett frischen VPS und schau zu, wie er sich in einen voll gehärteten WordPress- oder Nextcloud-Server mit TLS und Monitoring verwandelt – wie eine Art Infrastruktur-Pokémon-Entwicklung. 🐛➡️🐉
Kein manuelles Herumgefummel per SSH.
Keine mysteriösen Einrichtungsschritte.
Kein „TODO: später dokumentieren“-Friedhof. 💀
Alles ist idempotent – du kannst es jederzeit erneut laufen lassen, ohne deine Daten zu zerschießen oder Configuration-Drift-Dämonen zu beschwören.
⚙️ Der Stack auf einen Blick
- 🏗️ K3s – Kubernetes ohne das Enterprise-Trauma
- 🔀 F5 nginx-ingress – läuft als DaemonSet mit
hostNetwork: true - 🔒 cert-manager – automatische Let’s-Encrypt-Zertifikate, weil Browser sich nach grünen Schlössern sehnen
- 📝 WordPress 6.9-fpm + nginx-Sidecar + MariaDB 10.11
- ☁️ Nextcloud 33-fpm + Redis + Collabora CODE für selbst gehostetes Office in Nerd-Qualität
- 📊 Prometheus + Grafana – denn existiert etwas überhaupt, wenn man es nicht plotten kann?
- 🛡️ iptables – Default DROP, Portscan-Erkennung, ICMP-Rate-Limiting, ein kleiner digitaler Burggraben 🏰
- 🔐 Fail2Ban, auditd, rkhunter, dnf-automatic – Paranoia as Code™
🚀 Was ein einziger Playbook-Lauf tatsächlich macht
- 🔑 Härtet SSH – eigener Port, nur Key-Authentifizierung, strengere Konfiguration
- 🔥 Baut Firewall-Regeln für IPv4 + IPv6 mit Portscan-Erkennung über
xt_recent - 🧱 Schaltet SELinux auf Enforcing, mit korrekten Container-Kontexten
- ☸️ Installiert K3s, Helm, cert-manager und nginx-ingress
- 📦 Rollt den kompletten Kubernetes-Workload-Stack automatisch aus
- 📝 Konfiguriert WordPress per WP-CLI wie ein zivilisierter Automatisierungskobold
- ☁️ Konfiguriert Nextcloud per
occ, inklusive Redis, SMTP und Trusted Domains - 📈 Richtet Monitoring-Exporter, Prometheus-Scraping und Grafana-Dashboards ein
- 🛡️ Rollt Fail2Ban, auditd, rkhunter-Scans und automatische Sicherheitsupdates aus
- ☕ Verbraucht vermutlich weniger Kaffee als ich beim Debuggen
🔐 Secrets & Sicherheit
Alle Zugangsdaten sind mit Ansible Vault (AES-256) verschlüsselt.
Sensible Dateien wie:
vault.ymlvars.ymlhosts.yml
…landen nie im öffentlichen Repository. 🚫🌍
Das GitHub-Repo enthält nur wiederverwendbaren Automatisierungscode und `.example`-Vorlagen:
vars.yml.example
vault.yml.example
hosts.yml.exampleKlonen → Werte eintragen → verschlüsseln → ausrollen. ✨
🙃 Dinge, die viel schwieriger waren als gedacht
- Let’s-Encrypt-HTTP-01-Challenge liefert 301
Wer alles auf HTTPS umleitet, leitet eben auch die ACME-Challenge um. Wer hätte das ahnen können? 🙃
Gelöst mit F5 Mergeable Ingresses (Master/Minion-Muster), sodass/.well-known/an den Redirects vorbeikommt.
- Let’s-Encrypt-HTTP-01-Challenge liefert 301
„`
- Endlose HTTPS-Redirect-Schleife
Meine erste nginx-Logik hat sich quasi philosophisch selbst geDDoSt.
Gelöst mit einem saubereren Redirect-Muster aus drei Variablen.
„`
- Endlose HTTPS-Redirect-Schleife
„`
- mysqld_exporter v0.19.0 hat
DATA_SOURCE_NAMEabgeschafft
Zugangsdaten brauchen jetzt eine gemountete.my.cnf-Datei.
Außerdem gelernt:0600-Rechte helfen nicht, wenn der Container alsnobodyläuft. 🤡
„`
- mysqld_exporter v0.19.0 hat
„`
- iptables OUTPUT DROP hat K3s-Interna lahmgelegt
Denn Kubernetes redet offenbar ununterbrochen mit sich selbst.
Gelöst mit expliziten ACCEPT-Regeln für die Pod-/Service-CIDRs.
„`
- iptables OUTPUT DROP hat K3s-Interna lahmgelegt
„`
- Grafana-Dashboard 1860 zeigte „No data“
Moderne Grafana-Dashboards enthalten kein__inputsmehr.
Lösung: ein winziges Python-Patch-Skript, das wie ein kleiner Automatisierungskobold mit der Grafana-API plaudert.
„`
🧪 Probier es selbst aus
git clone https://github.com/aptupgrademe/www_k3s.git
cd www_k3s
cp inventory/hosts.yml.example inventory/hosts.yml
cp inventory/host_vars/test/vars.yml.example inventory/host_vars/myhost/vars.yml
# fill in your values, then:
ansible-vault encrypt inventory/host_vars/myhost/vault.yml
ansible-playbook blog.yml --limit myhost --ask-vault-passDen vollständigen Quickstart, die Rollenübersicht und die Doku der Variablen findest du in der README auf GitHub.
PRs, Feedback und andere Infrastruktur-Nerds sind willkommen. 🚀🐧☸️




