Welches Problem löst dieser Beitrag?

Viele persönliche Blogs kommen nicht deshalb ins Stocken, weil die Website schwer zu bauen wäre. Sie stocken, weil sich das Veröffentlichen schwerfällig anfühlt. Jeder neue Beitrag bedeutet Konfiguration anfassen, manuell neu bauen, Dateien hochladen und dieselben Deployment-Schritte wiederholen.

Ich wollte einen leichteren Workflow: Markdown lokal schreiben, zu GitHub pushen und GitHub Actions die Website automatisch bauen und veröffentlichen lassen. Damit wird Publizieren zu einer wiederholbaren Gewohnheit statt jedes Mal zu einer kleinen Ops-Aufgabe.

Wann dieses Setup passt

  • du betreibst einen persönlichen Blog, eine technische Publikation oder eine leichte Docs-Seite
  • Inhalte sollen als Markdown-Dateien in Git liegen
  • du möchtest weder WordPress noch ein schweres CMS-Backend
  • du möchtest zweisprachige Inhalte ohne manuell gepflegte Übersetzungs-Mappings

Wenn du zuerst ein visuelles Editorial-Backend, Multi-Author-Freigaben oder Online-Editing brauchst, ist dieses Modell wahrscheinlich nicht ideal.

Das Ergebnis

Sobald der Workflow eingerichtet ist, sieht die Veröffentlichung eines neuen Beitrags so aus:

  1. lokal ein zweisprachiges Post-Gerüst erzeugen
  2. chinesische und englische Markdown-Datei bearbeiten
  3. Website lokal prüfen
  4. git push origin main
  5. GitHub Actions das Update deployen lassen

Diese Trennung ist wichtig. Schreiben bleibt auf Inhalte fokussiert, Deployment wird Automation.

Umgebungs-Checkliste

Der aktuelle Stack dieses Blogs:

  • Framework: Astro
  • Content Layer: astro:content
  • Content-Format: Markdown
  • Deployment-Modell: statisches Artifact Release
  • Webserver: Nginx
  • CI/CD: GitHub Actions

Beiträge liegen in einer zweisprachigen Verzeichnisstruktur:

src/content/posts/zh-cn/*.md
src/content/posts/en-us/*.md

Jede Sprache hat eine eigene Datei, beide teilen aber denselben path. Dadurch erzeugt die Website:

  • Chinesisch: /posts/<path>/
  • Englisch: /en/posts/<path>/

Schritt für Schritt

1. Das Content-Modell früh festlegen

Wenn sich das Content-Modell ständig ändert, wird jeder neue Artikel zur Code-Aufgabe statt zur Schreibaufgabe.

In diesem Projekt leben Posts, Pages, Categories und Resources alle in astro:content. Die wichtigste Regel ist:

  • Posts verwenden path
  • Pages und Categories verwenden key

Damit sollte ein neuer Artikel nur neue Markdown-Dateien benötigen und keine Änderung an der Route-Mapping-Logik.

2. Einen Scaffold-Befehl für neue Posts hinzufügen

Alte Dateien per Hand zu kopieren funktioniert eine Zeit lang, wird aber immer unordentlicher.

Ich habe ein einfaches Skript hinzugefügt, sodass ein neuer Artikel so erzeugt werden kann:

npm run new:post -- "markdown-blog-publish-workflow" "本地写 Markdown,git push 后自动上线:我的双语博客发布流程" "Write Markdown Locally, Deploy on git push: My Bilingual Blog Publishing Workflow" writing

Dadurch entstehen sofort zwei Draft-Dateien:

src/content/posts/zh-cn/markdown-blog-publish-workflow.md
src/content/posts/en-us/markdown-blog-publish-workflow.md

Sie werden mit folgendem Wert angelegt:

draft: true

Dieser Default ist wichtig, weil er verhindert, dass halbfertige Inhalte automatisch veröffentlicht werden.

3. Lokale Arbeit auf Schreiben und Vorschau begrenzen

Während des Schreibens interessieren mich nur zwei Dinge:

  1. Markdown bearbeiten
  2. mit npm run dev Vorschau ansehen

Die lokalen Checks sind unkompliziert:

  • erscheint der Beitrag auf der Startseite
  • rendern beide Sprachversionen korrekt
  • aggregieren Kategorien und Tags korrekt
  • funktionieren Titel und Description für SEO

Wenn diese Phase solide ist, gibt es kaum einen guten Grund, weiter manuell per SSH zu deployen.

4. Deployment an GitHub Actions übergeben

Dieser Schritt macht den Workflow nachhaltig.

Der aktuelle Produktionsablauf:

  1. auf main pushen
  2. npm ci ausführen
  3. npm run build ausführen
  4. dist archivieren
  5. über SSH hochladen
  6. nach releases/<timestamp>-<sha> entpacken
  7. current umschalten
  8. öffentliche Verfügbarkeit prüfen

Ab diesem Punkt ist die Veröffentlichung eines Artikels keine manuelle Release-Aufgabe mehr, sondern normales CI/CD.

5. Den Server nur statische Dateien ausliefern lassen

Ein Prinzip ist mir besonders wichtig: Der Server soll ausliefern, nicht bauen.

Das hat sofort mehrere Vorteile:

  • weniger bewegliche Teile in Produktion
  • konsistentere Build-Umgebung
  • einfacheres Rollback
  • klareres Debugging bei Fehlern

Die Live-Verzeichnisstruktur sieht so aus:

/var/www/aitokenhacks.com/releases/<release-id>
/var/www/aitokenhacks.com/current

Jedes Release ist isoliert, und das Publizieren besteht im Wesentlichen aus dem Umschalten eines Symlinks.

6. Diagnostik in den Deployment-Workflow aufnehmen

Automation ist nicht fertig, nur weil eine YAML-Datei existiert. Sie wird erst nützlich, wenn Fehler leicht verständlich sind.

Deshalb habe ich Deployment-Diagnostik ergänzt für Dinge wie:

  • welches Deploy-Secret fehlt
  • ob SSH-Zugriff funktioniert
  • ob Remote-Verzeichnisse existieren
  • auf welches Release current umgeschaltet wurde

So endet ein fehlgeschlagenes Deployment nicht mit einem beliebigen roten Badge. Man sieht, ob das Problem bei GitHub Secrets, SSH-Authentifizierung, Verzeichnisberechtigungen oder öffentlicher Verifikation liegt.

Häufige Fragen und Probleme

Warum nicht einfach ein Online-Backend verwenden?

Weil das Hauptziel dieser Seite Content-Aufbau und SEO ist, nicht Editor-UX.

Markdown-Dateien in Git geben mir Dinge, die mir wichtiger sind:

  • vollständige Versionshistorie
  • Rollback
  • überprüfbare Änderungen
  • Content direkt neben Code
  • keine Abhängigkeit von einem fremden Admin-Panel

Warum nicht beide Sprachen in einer Datei speichern?

Weil eine einzelne Datei mit dupliziertem Frontmatter und doppeltem Body sehr schnell schwer wartbar wird.

Zwei Dateien mit identischem path erwiesen sich als deutlich sauberer:

  • passt natürlich zu Astro Content Collections
  • Body-Inhalt bleibt leicht editierbar
  • keine zusätzliche Translation-Mapping-Schicht nötig

Was schlägt bei automatisiertem Deployment am häufigsten fehl?

In der Praxis bin ich vor allem auf zwei wiederkehrende Problemklassen gestoßen:

  • Billing- oder Quota-Probleme bei GitHub Actions, bei denen der Job nie wirklich startet
  • fehlende oder falsche Deploy-Secrets, bei denen das SSH-Setup sofort scheitert

Meine normale Debug-Reihenfolge ist daher:

  1. ist der Workflow überhaupt gestartet
  2. sind die Deploy-Secrets vorhanden
  3. funktionieren SSH-Benutzer und Key
  4. erlaubt das Remote-Verzeichnis das Publizieren

Abschließender Gedanke

Beim Aufbau eines persönlichen technischen Blogs würde ich Schreiben und Release-Mechanik klar trennen.

Beim Schreiben zählt die Qualität des Beitrags. Beim Veröffentlichen sollte CI/CD die wiederholbaren Schritte übernehmen.

Sobald der Workflow zu „Markdown lokal schreiben, dann git push“ wird, wird der Blog endlich zu etwas, das man dauerhaft konsistent weiterführen kann.