Markdown lokal schreiben, mit git push deployen: mein zweisprachiger Blog-Publishing-Workflow
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:
- lokal ein zweisprachiges Post-Gerüst erzeugen
- chinesische und englische Markdown-Datei bearbeiten
- Website lokal prüfen
git push origin main- 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:
- Markdown bearbeiten
- mit
npm run devVorschau 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:
- auf
mainpushen npm ciausführennpm run buildausführendistarchivieren- über SSH hochladen
- nach
releases/<timestamp>-<sha>entpacken currentumschalten- ö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
currentumgeschaltet 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:
- ist der Workflow überhaupt gestartet
- sind die Deploy-Secrets vorhanden
- funktionieren SSH-Benutzer und Key
- 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.