Brauche ich für diesen Blog überhaupt WordPress und Kubernetes? Ein Hugo-Experiment, echte Zahlen und was eine Migration wirklich kostet

Ich habe einen Teil dieses Blogs in Hugo nachgebaut und mit WordPress auf K3s verglichen: Tempo, Hardware, Patchen, Sicherheit, Grafana, Ansible-Rollen und Migrationsaufwand. Die Entscheidung ist noch offen.

Browser showing the Hugo test copy of the blog, with an arrow labelled Test Migration from the WordPress logo to the Hugo logo and a Proof of Concept badge

🌐 Auch auf: English · Français · Español

Update vom 6. November 2026: Inzwischen ist es entschieden und umgesetzt: Dieser Blog läuft jetzt auf Hugo. Was dabei passiert ist, steht hier.

Kurz gesagt: Dieser Blog besteht im Kern aus Text und Bildern, läuft aber auf Kubernetes mit Datenbank, PHP-Pool, Cache und zehn Plugins. Also habe ich einen Teil davon als statische Seite mit Hugo nachgebaut und beides verglichen. Das Ergebnis hat mich in beide Richtungen überrascht: Für die Leser ist der Tempogewinn kleiner als gedacht, für den Betrieb ist der Gewinn deutlich größer. Entschieden ist nichts. Dieser Blog läuft weiter auf WordPress.

In der Vergangenheit war mir Hugo zu umständlich, zu aufwendig und zu wenig benutzerfreundlich, sowohl in der Nutzung als auch beim Umbau von WordPress. Mit schneller KI-Unterstützung sieht das heute komplett anders aus: Umwandlung, Theme und Prüfskripte für diesen Test entstanden in kurzer Zeit. Deshalb stelle ich mir die Frage jetzt neu.

Dieser Beitrag sammelt alles, was ich vor einer Entscheidung wissen möchte: Messwerte, klar gekennzeichnete Schätzungen, die Folgen für jede Ansible-Rolle, Grafana, SELinux, die Frage nach einem neuen Repository, den echten Aufwand und eine Checkliste für den Fall, dass ich es wirklich mache.

Inhaltsverzeichnis

🧒 Für Nicht-ITler: Was ist der Unterschied?

WordPress baut eine Seite, wenn jemand sie aufruft: Ein Programm liest den Text aus einer Datenbank und setzt die Seite zusammen, ein Cache hebt das fertige Ergebnis eine Weile auf. Hugo baut alle Seiten einmal im Voraus auf meinem eigenen Rechner. Der Server gibt danach nur noch fertige Dateien aus. Für einen Besucher läuft kein Programm, es gibt keine Datenbank und keine Login-Seite, die jemand angreifen könnte.

Der Preis: Es gibt keinen bequemen Editor im Browser mehr. Ein Beitrag ist eine Textdatei, und Veröffentlichen heißt bauen und hochladen.

Was man mitnimmt: WordPress ist ein laufendes Programm, das Seiten ausliefert. Hugo ist ein Werkzeug, das Dateien erzeugt. Fast jeder Unterschied in diesem Beitrag folgt daraus.

🧪 Das Experiment: drei Beiträge, alle Seiten, vier Sprachen

Ich habe die drei neuesten Beiträge und alle statischen Seiten auf Englisch, Deutsch, Französisch und Spanisch nach Markdown umgewandelt und ein kleines Theme mit denselben Farben, Schriften und demselben Seitenaufbau geschrieben. Ein Beitrag sieht auf der Platte jetzt so aus:

---
title: 'HTTP/3 für Blog und Nextcloud'
slug: http-3-fur-blog-und-nextcloud
date: '2026-11-03T19:59:27+01:00'
translationKey: wp3277
categories: [DevSecOps]
image: img/2026_11_no_http3.webp
---

**Update vom 4. November 2026:** HTTP/3 ist auf allen meinen Servern wieder aus.

Für Leser verhält sich die Seite gleich: gleiches Menü, Sprachflaggen, Laufband, Slider, Beitragsliste, Seitenleiste, Inhaltsverzeichnis und Suche. Die kleinen Unterschiede sieht man nur im direkten Vergleich. Das Theme ist ein eigener Nachbau und keine Kopie des WordPress-Themes, deshalb weichen einzelne Pixel ab.

Ähnliches Aussehen beweist wenig. Deshalb hat ein Skript jede Seite mit dem Original verglichen:

GeprüftErgebnis
Seiten im Vergleich mit dem WordPress-Original28 von 28 im Text identisch
Code-Blöcke, Zeichen für Zeichen24, kein Unterschied
Tabellen, Überschriften, Listenpunkte20, 251 und 300, Anzahl identisch
Links im Artikeltext84, alle korrekt
Adressen, Canonical, hreflang, noindexAuf allen 28 Seiten identisch
Interne Verweise im gesamten Build7.740 in 225 HTML-Dateien, 0 kaputt
Bauzeit1,9 s beim ersten Mal, danach 0,14 s
Umfang von Theme und Werkzeugen561 Zeilen Theme, 217 Zeilen Python

Der Test hat auch die Fehler gefunden, für die er gedacht ist. Hugo ersetzte tel:-Links in meinem Impressum stillschweigend durch #ZgotmplZ. Monatsarchive in den anderen Sprachen landeten im englischen Pfad. Meine erste Fassung zeigte die Meta-Beschreibung statt des echten Einleitungstextes. Und das Logo war gespiegelt. Den ersten Fehler fand nur das Vergleichsskript; einen Telefon-Link hätte ich nie angeklickt.

Was man mitnimmt: Eine Migration ist nur so gut wie ihr automatischer Vergleich. Eine Seite, die richtig aussieht, kann trotzdem kaputten Inhalt haben.

⚡ Tempo: was ich gemessen habe und was ich nur schätze

Zuerst die Messwerte. Sie liefen von meinem Heimserver gegen den echten Blog, 14 Anfragen pro Zeile, gemessen wurde die Zeit bis zum ersten Byte. Eine statische Datei auf dem Live-Server steht dabei stellvertretend für das, was eine Hugo-Seite liefern würde.

AnfrageMedianSpanne
Statische Datei57 ms50–59 ms
Startseite aus dem WordPress-Seitencache58 ms55–62 ms
Beitrag aus dem WordPress-Seitencache60 ms56–63 ms
Derselbe Beitrag, von PHP erzeugt (Cache umgangen)146 ms134–163 ms

Das ist die Überraschung: Eine gecachte WordPress-Seite ist so schnell wie eine statische Datei. Der Cache macht seine Arbeit bereits. Der Unterschied zeigt sich erst, wenn der Cache nicht greift.

Klarer ist der Gewinn bei der Menge, die ein Browser laden muss, ohne Bilder und Schriften:

Startseite, komprimiertWordPressHugoÄnderung
HTML19,4 KB4,9 KB−75 %
CSS8 Dateien, 67,7 KB1 Datei, 3,6 KB−95 %
JavaScript16 Dateien, 111,1 KB1 Datei, 1,0 KB−99 %
Gesamt25 Dateien, 198 KB3 Dateien, 9,5 KB−95 %

Jetzt die Schätzungen. Das sind meine Erwartungen, keine Messungen. Einen echten Browser-Test unter realistischen Bedingungen habe ich noch nicht gemacht.

SituationErwarteter GewinnGrundlage
Seite liegt schon im WordPress-CacheEtwa 0 %Gemessen: 57 gegen 58 ms
Seite liegt nicht im CacheEtwa 60 % kürzere Wartezeit, rund 2,5-mal so schnellGemessen: 146 gegen 57 ms
Erster Besuch mit dem Handy bei mäßiger VerbindungGrob 20–40 % schneller, bis die Seite nutzbar istSchätzung aus 95 % weniger CSS und JavaScript
Weitere Seiten im selben BesuchGeringDateien liegen schon im Browser-Cache
BesucherspitzeDeutlich robusterKein Worker-Limit und keine Datenbank im Weg

Was man mitnimmt: Tempo allein würde eine Migration nicht rechtfertigen. Ein gut gecachtes WordPress ist bereits schnell. Leser gewinnen vor allem durch weniger Code zum Herunterladen, am meisten auf dem Handy.

🖥️ Hardware: was der Server wirklich bräuchte

Das sind die heutigen Werte des Blog-Servers und meine Schätzung für eine statische Seite. Grafana und das gesamte Monitoring bleiben in beiden Fällen, weil ich sie behalten will.

WertWordPress auf K3s (gemessen)Hugo (Schätzung)
CPU4 Kerne, Last etwa 0,21–2 Kerne
Belegter Arbeitsspeicher2,7 GB von 7,5 GBEtwa 1,0–1,2 GB
Sinnvolle Servergröße4 GB oder mehr2 GB
Kubernetes-Daten auf der Platte7,1 GB0
Website auf der Platte375 MB Anwendung und MedienUnter 500 MB für alle Beiträge
Laufende Pods / Container-Images17 / 140 / 0
Hintergrundjob alle paar Minutenwp-cronKeiner
Firewall-Regeln (Ausgabe von nftables)7.760 Zeilen, meist von K3sEinige hundert Zeilen

Wohin der Speicher heute geht, nach belegtem Speicher pro Prozess. Die Werte überschneiden sich, ihre Summe liegt also über dem echten Verbrauch:

TeilSpeicherMit Hugo
k3s-server847 MBFällt weg
containerd und seine Shims383 MBFällt weg
php-fpm349 MBFällt weg
MariaDB249 MBFällt weg
Ingress (nginx und Controller)316 MBErsetzt durch ein kleines nginx
Grafana357 MBBleibt
Alloy273 MBBleibt
Loki179 MBBleibt
Prometheus175 MBBleibt

Was man mitnimmt: Die Website selbst bräuchte fast nichts. Das Monitoring wäre mit rund 1 GB der größte Posten auf dem Server und bestimmt dann die Mindestgröße.

📅 Täglicher Aufwand und Patchen

Seit dem 1. September gab es in diesem Repository 256 Commits, 76 davon berührten die drei großen Blog-Rollen. Das ist nicht alles Wartung, denn vieles war Aufbau. Es zeigt aber, wohin die Aufmerksamkeit geht. Der Update-Tag und die zwei PHP-Lücken an einem Tag zeigen gut, was das praktisch bedeutet.

AufgabeWordPress auf K3sHugo
Betriebssystem-UpdatesJaJa
K3s, Helm, Ingress, cert-managerJaEntfällt
WordPress, 10 Plugins, ThemeJa, automatisch mit PrüfungenEntfällt
PHP, auch Notfall-PatchesJaAuf dem Server entfällt es
MariaDB und RedisJaEntfällt
Festgelegte Versionen für den Blog9 von 30 Einträgen, dazu der gemeinsame K3s-Stacknginx aus dem System, Hugo auf meinem Rechner
Nächtlicher Image-Scan und seine BefundeJa, siehe TrivyEntfällt; die Systempakete bleiben
Alarme zu Workern, Pods, DatenbankJaEntfällt
Caches leeren nach einer ÄnderungSeiten-, Objekt- und Optimierer-CacheEntfällt
Monitoring- und Sicherheits-Mails lesenJaJa, mit viel weniger Anlässen
Einen Beitrag schreibenEditor im BrowserTextdatei, Git, bauen, hochladen
Wenn ein Update etwas zerstörtDie Live-Seite kann ausfallenDer Build schlägt fehl, die Live-Seite bleibt, wie sie ist
RückwegDatenbank-Dump und Dateien zurückspielenVorherigen Build hochladen

Die Nextclouds bleiben auf K3s, mein Update-Tag verschwindet also nicht. Er wird nur kürzer.

Was man mitnimmt: Das ist der eigentliche Gewinn. Ganze Klassen von Updates, Notfällen und Alarmen verschwinden, weil die Software auf dem Server nicht mehr existiert.

🔐 Sicherheit: eine ehrliche Bewertung

Diese Bewertung ist meine Einschätzung, keine Messung. „Hoch“ bedeutet hier hohes Risiko.

BedrohungWordPress auf K3sHugoWarum
Lücke in Plugin oder CoreMittel bis hochKeineAuf dem Server läuft kein Code
Remote Code Execution in PHPMittelKeineKein PHP
SQL-InjectionNiedrig bis mittelKeineKeine Datenbank
Gestohlener Admin-LoginNiedrig, dank 2FA und Geo-FilterKeineEs gibt keinen Web-Login
Datenverlust nach einem EinbruchMittelNiedrigKeine Nutzerdaten; ein sauberer Neuaufbau genügt
Lücke in nginxMittelMittelBleibt
Kernel oder BetriebssystemMittelMittelBleibt
SSH oder Deploy-SchlüsselNiedrigNiedrig bis mittelDer Deploy-Schlüssel wird das wertvolle Geheimnis
Build-Kette (Hugo, Theme, mein Rechner)Nicht relevantNiedrig bis mittelNeu: Ein vergifteter Build würde veröffentlicht
Grafana-LoginNiedrig bis mittelNiedrig bis mittelBleibt und wird zum größten Web-Ziel
Kubernetes als AngriffsflächeNiedrig bis mittelKeineKein API-Server

Zwei unbequeme Punkte. Erstens heißt „statisch“ nicht „sicher“: Server, SSH, nginx und DNS brauchen dieselbe Sorgfalt, und meine neun Schutzschichten werden nicht überflüssig. Zweitens ist der Host mit Grafana eben nicht rein statisch. Dort gibt es weiterhin einen Login, und der verdient die größte Aufmerksamkeit.

Was man mitnimmt: Die Angriffsfläche schrumpft deutlich, weil mehrere Angriffsklassen nichts mehr treffen. Die verbleibenden Risiken wandern zum Deploy-Schlüssel und zu Grafana.

🧱 Brauche ich auf dem Blog-Server noch K3s?

Technisch nein. Warum ich es gewählt habe, erklären der K3s-Deep-Dive und der Beitrag zu WordPress auf Kubernetes. Ein einzelnes nginx mit einem Ordner voller Dateien braucht keinen Orchestrator. K3s hat aber Vorteile, die ich wirklich verlieren würde:

AspektMit K3sOhne K3s
Speicher und Platte➖ Etwa 1,2 GB RAM und 7,1 GB Platte➕ Nichts
Bewegliche Teile➖ API-Server, Kubelet, containerd, CNI, Ingress, cert-manager➕ Ein Dienst
Firewall➖ K3s fügt Tausende Zeilen hinzu; Vorsicht bei jeder Änderung➕ Nur meine eigenen Regeln
Updates➖ K3s, Charts und Images➕ Systempakete
Hochverfügbarkeit➖ Auf einem Knoten ohnehin keine➖ Auch keine
Trennung der Teile➕ Pods, NetworkPolicies➖ Bei einem Dienst kaum nötig
Updates ohne Ausfall➕ Rolling Updates eingebaut➕ Ersetzt durch atomaren Ordnerwechsel
Dieselben Werkzeuge wie auf den Nextclouds➕ Eine Arbeitsweise➖ Zwei Arbeitsweisen
Testfeld für die Nextclouds➕ Kleiner Host bekommt K3s-Updates zuerst➖ Fällt weg; eine Test-VM müsste das übernehmen
Lernwert und Blogstoff➕ Hoch➖ Auf diesem Host geringer

Die Nextclouds sind ein anderer Fall: PHP, Collabora, Push und Cron-Jobs sind dort wirklich mehrere zusammenarbeitende Dienste.

Was man mitnimmt: Auf dem Blog rechtfertigt sich K3s nicht mehr durch technische Notwendigkeit, sondern durch Einheitlichkeit, Testen und Lernen. Das sind legitime Gründe, man sollte sie aber ehrlich so nennen.

📝 Welche Daseinsberechtigung WordPress weiterhin hat

Es wäre leicht, WordPress hier abzuschreiben. Das wäre falsch, denn es löst echte Probleme, die Hugo nicht löst:

Stärke von WordPressMit Hugo
Editor im Browser, für jeden nutzbarTexteditor und Git oder ein zusätzliches CMS-Werkzeug
Schreiben und Veröffentlichen vom HandyOhne Zusatzwerkzeuge umständlich
Mediathek mit Upload und SucheDateien in einem Ordner
Mehrere Autoren mit RollenNur über Git oder ein Zusatzwerkzeug
Kommentare und FormulareExterner Dienst nötig
Geplantes VeröffentlichenNur mit zeitgesteuertem Build
Plugins für fast allesSelbst bauen
SEO-Analyse beim Schreiben (Yoast)Meta-Tags ja, Live-Analyse nein
Übergabe an Nicht-TechnikerKaum möglich
Shop, Mitglieder, dynamische InhalteNicht das richtige Werkzeug

Das würde aus den heutigen Plugins:

PluginMit Hugo
PolylangIn Hugo eingebaut
Yoast SEOEigene Vorlagen: Titel, Meta, Open Graph, Schema, Sitemap. Einfacheres Schema, keine Analyse im Editor
Easy Table of ContentsIn Hugo eingebaut
AutoptimizeIn Hugo eingebaut (Minify)
CompressXHugo-Bildverarbeitung beim Bauen
WP Super Cache, Redis CacheNicht nötig
Two Factor, Limit Login AttemptsOhne Login nicht nötig
Classic EditorEntfällt

Dazu kommt ein persönlicher Punkt. Die meisten meiner letzten Beiträge entstehen mit KI-Unterstützung, der bequeme Editor zählt für mich also weniger als für die meisten Blogger. Für eine Markdown-Datei und einen Git-Commit wäre die Arbeit mit einem KI-Assistenten sogar einfacher als heute. Abhängig wäre ich trotzdem nicht: Markdown lässt sich mit jedem Texteditor bearbeiten.

Was man mitnimmt: WordPress bleibt die richtige Wahl, wenn andere Menschen schreiben, wenn man unterwegs veröffentlicht oder wenn die Seite mehr tut, als Inhalte anzuzeigen. Das falsche Werkzeug ist es nur, wenn nichts davon zutrifft.

📈 Wie viele WordPress-Seiten, wie viele Hugo-Seiten?

Hugo ist am Markt eine kleine Nische. Laut W3Techs, Stand 5. November 2026:

KennzahlWordPressHugo
Anteil an allen Websites39,5 %0,1 %
Anteil an Websites mit bekanntem CMS58,2 %0,2 %
Verhältnis bei allen WebsitesEtwa 400 : 11
Sterne auf GitHub21.519 (ein Spiegel; entwickelt wird anderswo)90.379
LizenzGPLApache 2.0

Diese Zahlen sind mit Vorsicht zu lesen. W3Techs nennt Anteile und keine absoluten Zahlen und erkennt statische Seiten nicht zuverlässig, Hugo ist also vermutlich untererfasst. Sterne messen das Interesse unter Entwicklern, nicht laufende Websites, und das WordPress-Repository ist nur ein Spiegel. Direkt vergleichen sollte man die beiden Werte nicht.

Etwas zeigen die Zahlen trotzdem: Millionen Menschen nutzen WordPress, ohne je ein Git-Repository gesehen zu haben, während Hugo gemessen an seinem Marktanteil eine ungewöhnlich große Anhängerschaft hat. Mein Eindruck, ohne harte Daten: Diesen Weg gehen vor allem die Nerds, und zwar aus Gründen, die zu diesem Beitrag passen: kein PHP, keine Datenbank, kein Login, wenig Angriffsfläche, Markdown und Git statt einer Weboberfläche. Eine schnelle Seite ist ein schöner Nebeneffekt. Bei vielen ist es vermutlich auch einfach die Freude an einem Aufbau, den man ganz versteht.

Was man mitnimmt: WordPress ist der sichere Mainstream mit dem größten Ökosystem, Hugo eine bewusst gewählte Nische. In der Minderheit zu sein ist in keine Richtung ein Argument.

🛡️ Würde SELinux einfacher?

Ja, im Web-Teil deutlich, verschwinden wird es aber nicht. Der SELinux-Deep-Dive zeigt, wie viel Arbeit darin steckt.

ThemaWordPress auf K3sHugo auf AlmaLinux
Paket für Container-Regelnk3s-selinux, für AlmaLinux 10 noch nicht stabilNicht nötig
Domänen für den Web-TeilContainer mit eigenen Kategoriennginx im gut getesteten httpd_t
DateienVolumes und Container-LabelsEin Ordner als httpd_sys_content_t
Relabeln nach einem K3s-DownloadPflichtEntfällt
Proxy zu GrafanaÜber den Ingress im PodEin Boolean oder ein gelabelter Port
Eigene Monitoring-Domänen (homelab_*)BleibenBleiben
Versteckte Verweigerungen durch dontauditMüssen geprüft werdenMüssen geprüft werden
Aufwand beim Umstieg—Neue Lernphase für nginx auf dem Host

Auf FreeBSD stellt sich die Frage ganz anders, denn dort gibt es kein SELinux. An seine Stelle treten Jails und das MAC-Framework.

Was man mitnimmt: Der schwierigste SELinux-Teil, Container samt ihrem Paket, fällt weg. Der Enforcing-Modus bleibt, und auch die Pflicht, die tatsächliche Domäne jedes Dienstes zu prüfen.

📊 Grafana bleibt. Was bedeutet das?

Grafana läuft heute als normaler Systemdienst, ist aber über den K3s-Ingress erreichbar. Das ist die wichtigste Abhängigkeit:

TeilHeuteMit HugoAufwand
Grafana-DienstSystemdienstUnverändertKeiner
Zugriff über /grafana/K3s-IngressReverse Proxy im nginx des Hosts, mit WebSocket-UnterstützungKlein
Geo-Filter für den LoginIm IngressUmzug ins nginx des HostsKlein
fail2ban für den Grafana-LoginLiest Pod-LogsLiest das nginx-Log, braucht neuen Pfad und FilterKlein
PrometheusNode, Kubelet, kube-state, MariaDB, PHP-FPMNode und ein nginx-ExporterKlein
Alloy und LokiLesen /var/log/podsLesen /var/log/nginx und das JournalMittel
Dashboard für ContainerVorhandenAuf diesem Host nicht mehrEntfernen
Dashboards für PHP-FPM, MariaDB, RedisVorhandenAuf diesem Host nicht mehrEntfernen
Alarme zu Workern, Pods, DatenbankAktivEntfernen, sonst melden sie NoDataMittel
Neu: nginx-Anfragen und FehlerÜber den IngressAus nginx-Exporter und LogsMittel
Neu: letzter erfolgreicher Deploy—Zeitstempel-Metrik mit AlarmKlein
Ablauf der TLS-ZertifikateMonit-Prüfung am IngressMonit-Prüfung am HostKlein
SpeicherEtwa 1 GBEtwa 1 GBBestimmt die Servergröße

Eine frühere Lehre gilt hier direkt: Entferne ich Metriken und vergesse eine Regel, meldet sie vielleicht nichts mehr und sieht für immer grün aus. Nach einer Migration würde ich deshalb den Zustand jeder Regel prüfen, nicht das Ausbleiben von Mails.

Eine Alternative wäre ein zentrales Grafana zu Hause, das von allen Servern sammelt. Das nähme den letzten Login vom Blog-Host, ist aber eine eigene Entscheidung mit eigenen Risiken.

Was man mitnimmt: Grafana zu behalten ist kein Hindernis. Es bedeutet aber, dass Reverse Proxy, Geo-Filter und ein Login auf dem Host bleiben und dass das Monitoring auf nginx statt auf Pods umgebaut werden muss.

🎭 Die Ansible-Rollen im Einzelnen

Meine erste Annahme war, dass kaum Rollen übrig bleiben. Das war falsch. Die meisten Rollen schützen den Host und nicht WordPress, also bleiben die meisten auch. Das sind die 29 Rollen in blog.yml, mit der Zahl der Zeilen, die sich auf Kubernetes beziehen:

RolleZeilenK8s-ZeilenMit Hugo
blog_k3s_deploy2.96269❌ Fällt weg
blog_wordpress1.47345❌ Fällt weg
common_k3s1.139186❌ Nicht auf diesem Host (Nextcloud behält sie)
common_kube_metrics2145❌ Nicht auf diesem Host
common_trivy40614❌ Nicht auf diesem Host (keine Images)
blog_packages2220🔄 Neu schreiben: nginx, ACME-Client, rsync
blog_verify47813🔄 Neu schreiben: Seite, Zertifikate, Links, Deploy
blog_visitor_stats2373🔄 Neuer Log-Pfad, gleiche Idee
common_version_check34049🔄 Neuer Blog-Zweig
common_version_active22317🔄 Neuer Blog-Zweig
common_fail2ban48742🔧 Neue Log-Pfade, WordPress-Jail entfällt
common_firewall1.17918🔧 Einfacher: keine K3s-Tabellen oder NodePorts
common_monit70212🔧 Keine Pod-Prüfung; nginx- und Deploy-Prüfung
common_grafana1.5520🔧 Weniger Dashboards und Alarme
common_loki8437🔧 Log-Dateien statt Pod-Logs
common_prometheus4511🔧 Andere Ziele
common_selinux2206🔧 Kein k3s-selinux; nginx-Regeln
common_selinux_monitoring3990🔧 Weniger Domänen
common_clamav2610🔧 Vermutlich aus: keine Uploads auf dem Server
common_cis_hardening5718🔧 K3s-Ausnahmen entfernen
common_auditd2524🔧 K3s-Pfade entfernen
common_sysctl3132🔧 K3s-Einstellungen entfernen
common_aide_refresh1011🔧 Web-Ordner bewusst ausgenommen
common_dnf_automatic2251🔧 Kleine Anpassung
common_ssh6500✅ Unverändert
common_msmtp1380✅ Unverändert
common_rkhunter1870✅ Unverändert
common_logrotate1150✅ Unverändert, nginx kommt dazu
common_node_exporter2731✅ Unverändert
ErgebnisRollen
❌ Fällt auf diesem Host weg5
🔄 Neu schreiben5
🔧 Anpassen14
✅ Unverändert5

In Zeilen gerechnet, würden von den rund 16.600 Zeilen, die der Blog heute durchläuft, etwa 6.200 dort nicht mehr gebraucht, also 37 %. Nur rund 4.400 davon verschwänden wirklich aus dem Repository, denn den Rest brauchen die Nextclouds. Die Ansible-Tour zum Blog würde zum historischen Dokument.

Natürlich müsste auch einiges neu entstehen:

NeuWas es tutUmfang
Rolle für die statische Seitenginx auf dem Host, Sicherheits-Header, Weiterleitungen, Grafana-ProxyMittel
ZertifikateACME-Client mit Erneuerung und nginx-Reload statt cert-managerKlein
DeployEingeschränkter Nutzer, rsync, neuer Ordner pro Release, atomarer Wechsel, letzte Stände behaltenKlein bis mittel
nginx-ExporterAnfragen und Fehler für PrometheusKlein
Build-PipelineHugo-Version festlegen, bauen, vergleichen, Suchindex, hochladenMittel
PrüfungLink-Check und Inhaltsvergleich bei jedem BuildAus dem Experiment vorhanden
WeiterleitungstabelleAlte Adressen wie der Feed und MedienpfadeKlein
BackupVereinfacht: Inhalte in Git, dazu Server-Konfiguration und LogsKlein

Was man mitnimmt: Die teuren Rollen fallen weg, die Sicherheitsbasis bleibt. Das ist eine gute Nachricht: Die über Monate aufgebaute Härtung geht mit.

📦 Ein neues Repository?

Mein Repository enthält derzeit beide Stacks. Die gemeinsamen Rollen entscheiden über die Play-Variable stack, und meine Regel lautet, dass jede Änderung für beide funktionieren muss. Ein Umstieg auf Hugo wirft die Frage auf, wie man das aufteilt:

MöglichkeitVorteilNachteil
A: Alles im bestehenden RepositoryEin Ort, eine HistorieJeder Beitrag und jedes Bild landet in der Ansible-Historie und läuft durch deren Lint; das Repository wächst mit den Medien
B: Neues Repository für Inhalt, Theme und Build. Ansible bleibtSaubere Trennung; keine Änderung an den gemeinsamen Rollen; eigene, einfache CIZwei Repositories; der Deploy muss sie verbinden
C: Komplette Trennung mit gemeinsamen Rollen als CollectionSauber bei mehreren NutzernVersionen und Releases für nur zwei Nutzer; hoher Aufwand
D: Eigenes Ansible-Repository für den Blog mit kopierten RollenVöllig unabhängigJeder Sicherheitsfix doppelt; die Kopien laufen auseinander

Ich würde Möglichkeit B wählen. Beiträge, Bilder, Theme und Build-Skripte kämen in ein neues Repository. Der Server bleibt im Ansible-Repository mit einem dritten Wert, stack: static. Die Rollen bleiben an einem Ort, und die Härtung muss nicht doppelt gepflegt werden. Zum Veröffentlichen reicht dann ein eingeschränkter Deploy-Schlüssel statt Zugriff auf den Ansible-Code und seinen Vault.

Der Preis ist aber real: Aus der Regel „funktioniert für beide Stacks“ wird „funktioniert für drei“. Umgekehrt verschwinden in vielen Rollen die WordPress-Zweige.

Was man mitnimmt: Inhalt und Infrastruktur ändern sich unterschiedlich schnell und tragen unterschiedliche Geheimnisse, gehören also in getrennte Repositories. Gemeinsame Härtung sollte man nicht kopieren.

🐡 Und auf FreeBSD?

Ich bin seit Jahren von FreeBSD begeistert, auch wenn es neben Linux eher ein Nischendasein führt. Es ist ein komplettes System aus einem Guss, mit sehr guter Dokumentation, Jails, ZFS und pf. Für diesen Blog hatte es trotzdem nie eine Chance, denn K3s hängt an Funktionen des Linux-Kernels und läuft dort nicht produktionsreif.

Genau das ändert Hugo. Ohne K3s, Container, PHP und Datenbank schrumpfen die Anforderungen auf nginx, einen ACME-Client, rsync und das Monitoring, und all das ist auf FreeBSD gewöhnliche Software. Die Komplexität, die mich an Linux gebunden hat, ist weg. Hier alle drei Varianten im Vergleich:

ThemaWordPress auf K3sHugo auf AlmaLinuxHugo auf FreeBSD
RAM mit vollem Monitoring (Schätzung)2,7 GBEtwa 1,0–1,2 GBEtwa 1,0–1,2 GB
Patchen➖ Viele Schichten➕ System und nginx➕ freebsd-update und pkg
Automatische Updates➕ Vorhanden➕ Vorhanden➖ Muss gebaut werden
Trennung der Dienste➕ SELinux und Pods➕ SELinux und systemd-Sandbox➖ Jails, gröber, aber einfach
Firewall und Sperren➕ Vorhanden➕ Vorhanden, einfacher➖ pf und fail2ban neu
Wiederverwendbare RollenAlle24 von 29, teils angepasstWenige; das meiste wäre neu
Grafana, Prometheus, Loki➕ Vorhanden➕ Vorhanden, angepasst➖ Pakete gibt es; Pfade und Regeln neu
Snapshots vor Updates➖ Keine➖ Standardmäßig keine➕ ZFS
Betrieb neben den Nextclouds➕ Gleich➕ Gleiches Betriebssystem➖ Zweite Plattform
Vorhandenes Wissen➕ Groß➕ Groß➖ Muss aufgebaut werden
Wert als BlogthemaSchon geschriebenMittel➕ Hoch

Die entscheidende Frage ist, ob sich dieser Aufbau ähnlich gut absichern lässt wie der heutige. Ich habe das Schicht für Schicht bewertet. Das ist eine Bewertung auf dem Papier: Auf FreeBSD habe ich es weder gebaut noch getestet.

SchichtHeute auf AlmaLinuxHugo auf FreeBSDBewertung
Paketfilternftablespf mit Tables🟢 Gleichwertig
SSH-Härtung, Geo-Filtersshd und nftables-Setssshd und pf-Tables🟢 Gleichwertig
Angreifer sperrenfail2banfail2ban mit pf🟢 Gleichwertig, neue Regeln nötig
nginx isolierenSELinux und systemd-SandboxJail, Inhalte nur lesend eingehängt🟢 Gut; einfach und leicht zu prüfen
Monitoring isolierenEigene SELinux-DomänenEine Jail pro Dienst🟡 Gröber, aber klare Grenzen
Feine Regeln pro ProzessSELinux Type EnforcementKeine direkte Entsprechung; MAC-Framework, Capsicum nur, wo die Software es unterstützt🔴 Schwächer
Angriffsfläche am WebserverMit WordPress: großStatische Dateien🟢 Viel kleiner als heute
Informationen zu Sicherheitslückendnf, Trivypkg audit und freebsd-update🟢 Gut
Audit-LogauditdOpenBSM🟡 Im Prinzip gleichwertig; Auswertung neu
Datei-Integrität, RootkitsAIDE, rkhunterAIDE, rkhunter, freebsd-update IDS🟢 Gleichwertig
Rückweg nach einem UpdatePakete, WiederherstellungZFS-Snapshots und Boot Environments🟢 Besser
HärtungsbasisCIS-Benchmark in meiner Rolle umgesetztMuss von Hand neu entstehen🟡 Aufwand; weniger fertiges Material
GrafanaHinter Geo-Filter und fail2banGenauso, in einer eigenen Jail🟡 Bleibt das größte Ziel
Erfahrung aus echten VorfällenMonate voller echter BefundeBeginnt bei null🔴 Anfangs schwächer

Meine Einschätzung: Ja, für eine statische Seite ließe sich FreeBSD insgesamt ähnlich gut absichern, nur mit anderen Mitteln. Wirklich verlieren würde ich die feine Kontrolle von SELinux pro Prozess. Bei einem WordPress mit PHP und Plugins täte das weh. Bei einem nginx, das aus einer Jail nur lesend Dateien ausliefert, fällt es weit weniger ins Gewicht, weil ein Angreifer dort schlicht viel weniger tun kann. Dafür sind Jails einfach genug, um sie mit bloßem Auge zu prüfen. Die zwei echten Schwachstellen sind Grafana, das weiterhin einen Login braucht, und meine fehlende Praxis: Mein AlmaLinux-Aufbau ist durch Monate echter Fehler gegangen, ein FreeBSD-Aufbau wäre das noch nicht.

Ein offener Punkt: Die Pakete für Grafana, Prometheus, Loki und node_exporter gibt es meines Wissens in den FreeBSD-Ports, Alloy und die aktuellen Versionen müsste ich aber erst prüfen. Andernfalls bräuchte es einen anderen Log-Sammler.

Was man mitnimmt: Der große Gewinn kommt von Hugo, nicht vom Betriebssystem. Aber erst Hugo macht FreeBSD überhaupt möglich: Ist K3s weg, ist die Wahl keine technische mehr. Sie wäre eine Überzeugungsfrage, und für eine statische Seite eine vertretbare.

💶 Kosten und Nutzen

PunktKostenNutzen
MigrationEinmalig, siehe unten—
Server—Kleinerer und günstigerer Server möglich
WartungNeue Build-Kette zu pflegenViel weniger Patchen und weniger Alarme
SicherheitDeploy-Schlüssel und Build schützenMehrere Angriffsklassen weg
Tempo—Weniger Download; besser bei Spitzen und ohne Cache-Treffer
SchreibenKein Editor, kein Handy-WorkflowGit-Historie, einfache Dateien, leicht mit KI
Backups—Viel einfacher
Übertragbarkeit—Markdown läuft überall; keine Datenbank-Bindung
WissenTestfeld für K3s fällt wegWeniger Sonderfälle im Kopf
SEORisiko beim Umzug; keine Yoast-AnalyseSchnelle Seiten und volle Kontrolle
BlogstoffWeniger Betriebsgeschichten von diesem HostEine gute Migrationsgeschichte

Einen Serverpreis kann ich hier nicht sinnvoll nennen, das hängt vom Anbieter ab. Die Ersparnis ist in jedem Fall überschaubar. Die eigentliche Währung ist hier Aufmerksamkeit.

Was man mitnimmt: Man bezahlt diese Migration nicht mit Geld und bekommt sie auch nicht in Geld zurück. Es ist ein Tausch: Bequemlichkeit beim Schreiben gegen deutlich weniger Betriebsarbeit.

⏱️ Wie viel Arbeit wäre das?

Der Blog hat 143 Beiträge in je vier Sprachen, insgesamt 572, dazu 16 statische Seiten und rund 1.400 Mediendateien. Die folgenden Werte sind Schätzungen. Das Experiment lief mit KI-Unterstützung an etwa einem Abend, die Umwandlung ist also vermutlich der kleinste Teil.

PhaseMit KI-UnterstützungHinweis
Bestandsaufnahme: Plugins, Sonderblöcke, Downloads2–3 hExport-Werkzeug vorhanden
Alle Beiträge und Medien umwandeln3–6 hSkript vorhanden; ältere Beiträge bergen Überraschungen
Theme fertigstellen: Seitennavigation, Tags, Archive, Handy3–5 hGrundlage vorhanden
SEO: Adressen, Weiterleitungen, Feed, Schema, Sitemap2–3 hAutomatischer Vergleich mit der heutigen Sitemap
Ansible: neue Rolle, 14 angepasst, 5 neu, Test-VM8–15 hDer größte Teil
Monitoring und Grafana3–5 hJede Regel prüfen
Backup, Restore-Test, Doku in drei Sprachen, Datenschutztext3–5 hMuss sorgfältig sein
Umstellung und aktive Beobachtung2–3 hDanach zwei Wochen Beobachtung
Gesamt, Hugo auf AlmaLinuxEtwa 26–45 hPraktisch verteilt auf 2–3 Wochen
Zusätzlich für FreeBSDEtwa 15–30 hWenige Rollen wiederverwendbar
Ohne KI-Unterstützung (grobe Vermutung)3–5 ArbeitswochenVor allem Theme, Umwandlung und drei Sprachen

Echte Läufe auf den Produktivservern, die Durchsicht jedes Diffs und die Entscheidungen bleiben bei mir. KI macht das Tippen schneller, nimmt aber nicht die Pflicht zum Prüfen ab.

Was man mitnimmt: Die meiste Arbeit steckt nicht in der Umwandlung, sondern in Ansible, Monitoring und Prüfung. Dort sollte man die Zeit einplanen.

✅ Was ich tun müsste, wenn ich mich für Hugo entscheide

  1. Anforderung klären: Kann ich ohne Browser-Editor und Handy-Workflow leben? Ohne diese Antwort ist alles andere egal.
  2. Plattform wählen: AlmaLinux als Standard, FreeBSD nur als bewusste Entscheidung.
  3. Vollständig sichern: Datenbank, Dateien und Medien. Die WordPress-Installation mehrere Wochen verfügbar halten.
  4. Inhalts-Repository anlegen mit Beiträgen, Medien, Theme und festgelegter Hugo-Version. Vor dem ersten Push alles auf Geheimnisse scannen.
  5. Alles umwandeln und jede Seite automatisch vergleichen: Text, Code-Blöcke samt Backslashes, Tabellen, Links, Alt-Texte, Titel und Beschreibungen.
  6. Jede Adresse behalten: Beiträge, Sprachen, Kategorien, Tags und auch /wp-content/uploads/, weil Bilder von außen verlinkt sind. Gegen die heutige Sitemap vergleichen.
  7. Weiterleitungen einrichten: Der RSS-Feed zieht ohne Konfiguration von /feed/ nach /index.xml. Auch ?p=-Links und die alte Suchadresse prüfen.
  8. Datenschutzerklärung neu schreiben und das Impressum prüfen. Der heutige Text beschreibt WordPress und seine Plugins. Auch den KI-Hinweis und die Lizenzen aller Downloads prüfen.
  9. Theme und SEO fertigstellen, samt Open-Graph-Bildern unter dem WhatsApp-Limit und noindex für die rechtlichen Seiten.
  10. Den Ansible-Teil auf einer Test-VM bauen: stack: static, die neue Rolle, die angepassten Rollen. Zweimal laufen lassen; der zweite Lauf muss changed=0 zeigen.
  11. SELinux wirklich prüfen: Domänen mit ps -eZ, versteckte Verweigerungen mit semodule -DB und das eigene Log jedes Dienstes.
  12. Monitoring umbauen: Grafana hinter nginx mit Geo-Filter und fail2ban, neuer Exporter, alte Regeln entfernen, dann den Zustand jeder Regel prüfen.
  13. Den Deploy-Weg absichern: eingeschränkter Schlüssel, atomarer Wechsel, letzte Releases behalten und ein Alarm, wenn der Deploy fehlschlägt.
  14. Eine Wiederherstellung testen: einen sauberen Server nur aus den Repositories bauen, bevor Produktion angefasst wird.
  15. Alles drumherum anpassen: Backup-Skripte, Prüfung von außen, Update-Check, Drift-Check, Betriebshandbücher in drei Sprachen und ein Hinweis an den älteren Deep Dives.
  16. Die Umstellung planen: DNS-TTL senken, ruhige Zeit wählen, Rückweg bereithalten und danach Suchmaschinen und Logs auf 404-Fehler prüfen.
  17. Zwei Wochen beobachten und erst dann WordPress und K3s vom Host entfernen.

Was man mitnimmt: Die meisten Punkte haben gar nichts mit Hugo zu tun. Es geht darum, keine Adressen zu verlieren, rechtlich korrekt zu bleiben, das Monitoring zu erhalten und einen Rückweg zu haben.

🌐 Würde HTTP/3 einfacher?

Teilweise. Wie im HTTP/3-Beitrag beschrieben, habe ich es abgeschaltet, weil Verbindungen nach einem Reload hingen. Mit nginx direkt auf dem Host wäre die Einrichtung einfacher, weil der Umweg über den Ingress wegfällt. Die Ursache bleibt aber: Alte Worker halten die UDP-Sockets fest. Das ist eine Sache von nginx, nicht von K3s, und deshalb habe ich Issue #1937 eröffnet. Weniger lange Verbindungen und seltene Reloads würden das Problem abmildern. Getestet habe ich das nicht. Auf einer statischen Seite wäre der Nutzen ohnehin klein, ich würde es also vorerst auslassen.

Was man mitnimmt: Eine einfachere Einrichtung behebt keinen Fehler in der Schicht darunter.

🎯 Die Lehren

  1. Erst messen, dann glauben. Ich habe einen großen Tempogewinn erwartet. Ein gecachtes WordPress antwortete in 58 ms, eine statische Datei in 57 ms.
  2. Der meiste Nutzen liegt im Betrieb. Software, die es nicht mehr gibt, braucht keinen Patch, keinen Alarm und keinen Notfall.
  3. Härtung überlebt. Meine Annahme, dass kaum Rollen bleiben, war falsch: 24 von 29 bleiben zumindest teilweise, weil sie den Host schützen.
  4. „Statisch“ ist nicht automatisch „einfach“. Grafana, Deploy und Build-Kette bleiben, und das Risiko wandert zum Deploy-Schlüssel.
  5. Eine Migration braucht ein Vergleichswerkzeug. Ohne es hätte ich die kaputten Telefon-Links im Impressum übersehen.

🤔 Wo ich gerade stehe

Ich habe mich nicht entschieden. K3s und WordPress sind für diesen Blog technisch nicht mehr nötig, so viel ist klar. Ebenso klar ist, dass sie mich Aufmerksamkeit kosten, die Leser aber nichts. Auf der anderen Seite stehen der Editor, das K3s-Testfeld für die Nextclouds und ein Aufbau, der funktioniert und den ich sehr gut kenne.

Wenn ich es mache, dann mit Hugo und einem getrennten Inhalts-Repository, das Monitoring bleibt. AlmaLinux ist die vernünftige Wahl, weil fast alles mitgeht. FreeBSD ist die Wahl, die mich begeistert, und zum ersten Mal wäre sie auf diesem Blog eine realistische. Und wenn es so weit ist, gibt es einen zweiten Teil mit den echten Zahlen, einschließlich allem, was diese Schätzungen falsch vorhergesagt haben.

Einige Texte und Bilder auf dieser Seite sind KI-gestützt oder KI-generiert. Details