← Zurück zum Blog

Warum ich keine großen Blog-Systeme mehr will – und wie diese Seite läuft

Warum ich keine großen Blog-Systeme mehr will – und wie diese Seite läuft

Früher war WordPress für mich gesetzt. Ein Server, MySQL, PHP, ein Theme, Plugins, fertig. Irgendwann wurde daraus: Zwei Server, ein Reverse Proxy, Redis-Cache, ein Page-Builder, Security-Plugins, Monitoring, ständige Updates, und eine Datenbank, die regelmäßig gecrasht ist.

Irgendwann hab ich die Bremse gezogen.

Was mich an großen Blog-Systemen stört

1. WordPress – die wartungsintensive Plattform

Faktor Aufwand
Updates Core + Plugins + Themes, oft wöchentlich
Sicherheit Ständig unter Beschuss, hardening nötig
PHP + MySQL Zwei Dienste, die gecared werden müssen
Backup Datenbank + Dateien, kein einfaches cp
Geschwindigkeit Ohne Caching langsam, mit Caching komplex

WordPress selbst ist nicht das Problem. Aber WordPress bedeutet automatisch drei Angriffsflächen: Core, Plugins, Themes. Jede Komponente muss aktuell sein, kompatibel bleiben, und darf sich nicht in die Quere kommen. Das ist kein Bloggen mehr, das ist Systemadministration.

2. Ghost – schlank, aber nicht schlank genug

Ghost ist moderner, hat weniger Angriffsfläche, und Node.js ist performant. Aber auch Ghost bedeutet: ein Server-Prozess, der läuft, eine Datenbank (SQLite oder MySQL), ein Reverse Proxy davor, und regelmäßige Updates. Plus: Ghost möchte in einer bestimmten Version laufen, hat Abhängigkeiten, und eine Migration ist aufwändiger als eine Markdown-Datei zu kopieren.

3. Der gemeinsame Nenner

Alle diese Systeme haben:

  • Eine Datenbank – Single Point of Failure, Backup ≠ cp
  • Einen laufenden Prozess – muss überwacht, gemonitort, gepatched werden
  • Ein Admin-Panel – Angriffsfläche, die man im Idealfall nicht braucht
  • Abhängigkeiten – PHP, Node, MySQL, Redis – alles Dinge, die kaputtgehen können

Diese Seite (frischux.de) – wie sie wirklich läuft

Die Dateistruktur

/var/www/html/
├── index.html              ← statisch
├── blog.html               ← vorgerendert (build-static.py)
├── post.html               ← dynamischer Fallback (JS)
├── impressum.html          ← statisch
├── statistik.html          ← täglich aus access.log generiert
├── artikel/                ← vorgerenderte Beitragsseiten
│   ├── paperless-ngx-dokumentenmanagement.html
│   └── *.html              ← alle Beiträge
├── css/style.css           ← einmal geschrieben, nie wieder angefasst
├── js/blog.js              ← ~170 Zeilen, eine Abhängigkeit (marked.js)
├── posts/
│   ├── posts.json          ← Metadaten, per Hand gepflegt
│   ├── *.md                ← Beiträge in reinem Markdown
│   └── feed.xml            ← Atom-Feed, per Hand aktualisiert
├── images/posts/           ← generierte KI-Bilder, lokal gecached
├── scripts/
│   ├── build-static.py     ← generiert artikel/*.html + blog.html + sitemap.xml
│   ├── download-images.py  ← lädt fehlende KI-Bilder nach
│   └── stats.py            ← baut statistik.html aus nginx-log
├── robots.txt
└── sitemap.xml             ← automatisch generiert

Keine Datenbank. Kein PHP. Kein laufender App-Server.

Der Hybrid-Ansatz: statisch + dynamisch

Dieses Blog fährt eine Mischstrategie:

  1. Statisch (primär): Ein Python-Script (scripts/build-static.py) rendert jeden .md-Beitrag in eine eigene HTML-Datei unter artikel/. Die Blog-Übersicht (blog.html) wird ebenfalls vorgerendert. Die Sitemap wird automatisch aktualisiert. Der statische Build läuft alle 20 Minuten per Cron – so sind händische Änderungen an Markdown-Dateien schnell sichtbar.
  1. Dynamisch (Fallback): Wer post.html?slug=artikel-name aufruft (z. B. über ein Lesezeichen), bekommt denselben Inhalt – gerendert via marked.js im Browser. Das ermöglicht einen fließenden Übergang für alte URLs.
  1. RSS/Atom: Der Feed in posts/feed.xml wird manuell gepflegt – ein Trade-off, den ich für die Einfachheit in Kauf nehme.

Wie ein Beitrag ausgeliefert wird (statischer Pfad)

  1. Der Browser ruft artikel/paperless-ngx-dokumentenmanagement.html auf
  2. nginx liefert die Datei direkt aus – kein PHP, kein JS, kein Datenbank-Query
  3. Die Seite ist in unter 100 ms da

Wie ein Beitrag ausgeliefert wird (dynamischer Pfad)

  1. Der Browser lädt blog.html und js/blog.js
  2. blog.js holt per fetch() die posts/posts.json
  3. Die Beitragsliste wird aus dem JSON gerendert
  4. Ein Klick auf einen Beitrag öffnet post.html?slug=...
  5. post.html lädt die .md-Datei und rendert sie via marked.js im Browser

Was automatisch passiert

Drei Cron-Jobs laufen im Hintergrund:

Alle … Script Aufgabe
5 Minuten stats.py Neue Zugriffe aus access.log auswerten (Bots gefiltert)
5 Minuten download-images.py Fehlende KI-Artikelbilder nachladen
20 Minuten build-static.py Geänderte Markdowns in statische HTMLs rendern

Was daran besser ist

Backup: CODEBLOCK1 Fertig. Kein MySQL-Dump, kein phpMyAdmin, kein "hab ich die Datenbank mitgesichert?".

Update eines Beitrags: CODEBLOCK2 Kein Login ins Admin-Panel, kein "wie hieß dieser eine Block-Editor-Shortcut noch?". Ein Editor, eine Datei, git commit, fertig.

Sicherheit: Es gibt keine Angriffsfläche. Kein PHP, keine Datenbank, kein Admin-Login. Die Seite exponiert nichts außer statischen Dateien – und einem nginx, der sie ausliefert.

Geschwindigkeit: Die statischen Seiten laden in ~50 ms. Kein PHP-FPM-Start, keine Datenbank-Connection, kein Rendering.

Was man verliert

Fairerweise: nicht jeder braucht das. Ein statischer Blog bedeutet:

  • Kein WYSIWYG-Editor – ich schreibe in Vim/Markdown
  • Kein Admin-Panel – kein Dashboard, keine Kommentare
  • Kein CDN-Plugin – Cloudflare oder ein einfacher nginx reichen
  • Keine User-Verwaltung – es gibt nur mich
  • Kein automatischer RSS-Feed – der Feed ist manuelle Handarbeit

Für Leser ändert sich nichts. Für mich ändert sich alles: Weniger Arbeit, mehr Kontrolle.

Fazit

Ich will nicht mehr administrieren, um zu bloggen. Ich will schreiben, eine Datei speichern, und fertig.

Diese Seite läuft auf einem einfachen nginx, hat keine Updates, keine Datenbank, kein PHP, kein JavaScript-Framework. Der einzige Build-Schritt ist ein Python-Script, das alle 20 Minuten kurz läuft. Die Seite ist zehnmal so schnell wie mein altes WordPress-Setup und hat genau null Angriffsfläche für App-Level-Exploits.

Manchmal ist die beste Technik die, die man nicht sieht – weil sie einfach nicht da ist.