Wie ich mein Serendipity-Blog aktualisiere
In de.comp.os.unix.linux.misc kam das Thema Serendipity (kurz: s9y) zur Sprache, insbesondere wie man das Blog im git halten und dann Updates einspielen kann. Da dieses Blog hier unter s9y läuft und ich es mit git verwalte, folgt hier mein Senf zu dem Thema.
Ich will nicht behaupten, dass mein Weg besonders toll oder sinnvoll ist, aber basierend auf meiner ganz persönlichen Erfahrung und dem Blick in meine git-Historie hat das die letzten 15 Jahre ganz prima funktioniert. Ich habe dabei die s9y-Updates von 1.2.0 bis 2.4.0 mitgenommen und die jeweils aktuellen Debian-Stables mit dem jeweils dazugehörigen PHP.
Disclaimer: Ich habe vermutlich ebenfalls seit 15 Jahren nicht mehr in die Anleitung geguckt, wie ein Update offiziell durchzuführen ist.
Grundsätzliches zu meiner Installation
Ich nutze keine Container oder sowas, s9y läuft einfach im Apache unter dem PHP-User (ich nutze php-fpm) und die Daten liegen in der hier laufenden MariaDB-Instanz (das scheint inzwischen ungewöhnlich zu sein, s9y wird heutzutage wohl primär mit SQLite getestet und entwickelt).
Da ich nicht möchte, dass der PHP-User überall schreiben darf und
irgendwelchen Unfug machen kann, habe ich einen zweiten User, dem alle
statischen Dateien gehören. Der PHP-User darf diese Dateien nur
lesen. Ausnahmen sind die beiden Verzeichnisse templates_c/
(der
Template-Cache) und uploads/
(Bilder usw., die übers Blog-Interface
hochgeladen werden): Hier ist es genau andersherum und nur der
PHP-User darf schreiben.
Ich habe kein zweites Staging- oder Testblog, dafür habe ich zu wenig Traffic. Wenn ich bastele, dann direkt im Live-Betrieb und wenn was kaputtgeht, ist es kaputt. Ist halt nur ein kleines privates Blog. Backups habe ich natürlich trotzdem.
git und mein Branchkonzept
Ich habe mir eine wilde(?) Branchlogik überlegt, in die mein Blog eingeteilt ist. Jeder Branch baut dabei auf dem vorherigen auf und wird regelmäßig darauf gerebased:
master
liegt ganz unten und enthält das eigentliche s9y, hier sind die Upstream-Sourcen ausgepackt. Die mitgelieferte.gitignore
ist bereits passend.mitch
enthält meine lokale Konfiguration: hier ist dieserendipity_config_local.inc.php
mit meiner DB-Konfiguration eingecheckt (auch wenn sie eigentlich in der.gitignore
steht) und in diesem Branch ist das Verzeichnisplugins/
mit den von mir verwendeten Plugins gefüllt.mitch-extra
enthält Fixes, Korrekturen und Hacks, die ich auf die installierten Plugins anwende. Jede Änderung wird einfach direkt eingecheckt. Aktuell sind hier ein paar Farbanpassungen für serendipity_event_geshi enthalten sowie kleinere Änderungen beim Versand von E-Mails[1].catreegory
enthält mein eigenes catreegory-Plugin. Das ist auch einfach stumpf nachplugins/
kopiert, ich habe keinerlei Automatismus, um das mit dem Plugin-Source-Repository synchron zu halten. Da passieren eh keine Änderungen, wenn nicht gerade etwas mit einer neuen PHP-Version kaputtgeht.twittercard
enthält noch ein eigenes Plugin – das habe ich seit der Erschaffung in 2016 komplett vergessen (es ist auch nur ein Commit – nie wieder angefasst). Es ist noch nicht mal auf GitHub veröffentlicht, peinlich, peinlich… Das Plugin setzt ein paar Metadaten in den HTML-Headern der Artikel, damit Twitter, Facebook & Co. bei Links auf das Blog eine Überschrift, ein Bild usw. extrahieren können (siehe Twitter Cards und Open Graph Protocol).restyle
ist der dickste Batzen an Commits, da ist alles drin, was ich am Blog geschraubt habe: CSS, Fonts, eigenes Template (sowas), Datenminimierung wegen DSGVO (sowas) usw.jquery-update
ist ein Update von JQuery auf eine weniger antike Version. Das basiert auf dem seit drei Jahren offenen Pull-Request #687, aber inzwischen mit einer noch aktuelleren JQuery-Version. Läuft mit den von mir benutzten Plugins seit den drei Jahren ohne Probleme.
Änderungen
Wenn ich jetzt irgendetwas ändern will, dann checke ich den
entsprechenden Branch aus (z.B. mitch
, wenn sich meine DB-Connection
geändert hat), committe dort die Änderung und rebase dann alle
Branches aufeinander. Dafür gibt es dieses kleine Skript mit dem
passenden Namen git-magic-blog
:
- git checkout mitch && git rebase master \
- && git checkout mitch-extra && git rebase mitch \
- && git checkout catreegory && git rebase mitch-extra \
- && git checkout twittercard && git rebase catreegory \
- && git checkout restyle && git rebase twittercard \
- && git checkout jquery-update && git rebase restyle \
- && git checkout jquery-update
Das ist total eklig, funktioniert aber insgesamt super.
Etwas gewöhnungsbedürftig ist, wenn ein einzelner Commit wegfällt,
weil sich irgendwas im Original-Code geändert hat: Dann muss ich in
dem Branch, in dem mein Commit lag, beim Rebase einmal git rebase
skip
aufrufen (so weit, so normal), und danach in allen darauf
folgenden Branches noch einmal. Das ist im ersten Moment
erschreckend und ungewöhnlich, bei genauerer Betrachtung aber logisch:
Der Commit war in allen darauf aufbauenden Branches drin und git
versucht bei jedem Folge-Rebase, ihn anzuwenden und stellt dann erneut
fest „hier ist ja gar nichts mehr zu tun, willst Du den Commit
überspringen?“.
Ebenso muss ich, wenn ich einen meiner Commits absichtlich droppe, ihn auch in allen Folge-Branches noch einmal droppen.
Das muss man wissen und dran denken, damit kann ich aber gut leben.
„Wartungsmodus“
Während ich den Branch gewechselt habe, läuft das Blog mehr oder
weniger weiter, ggf. aber nur auf einem Reifen: Ist der Branch
master
ausgecheckt, fehlt die DB-Konfiguration, da geht gar nichts
mehr. Ist mitch
ausgecheckt, fehlen mein Catreegory-Plugin und mein
gesamtes CSS und so weiter. Das Blog sieht dann sehr rustikal aus,
funktioniert aber grundlegend.
Wie gesagt: Das ist hier kein wichtiger Produktivbetrieb, damit kann
ich leben. Man könnte das git-Repository natürlich genausogut
irgendwo hinreplizieren, dort lokal die Änderungen durchführen und
dann nacheinander alle Branches in den Produktivbetrieb force-pushen
(oder einfach den ausgecheckten Branch jquery-updates
komplett auf
den Server rsync(1)en oder sowas).
Wenn ich z.B. etwas am CSS ändere, mache ich das im „kompletten Blog“
(also im Branch jquery-updates
) im laufenden Betrieb, bis es passt.
Visuelle Kontrolle direkt im Browser :)
Dann commit ich die Änderung, checke meinen restyle
-Branch aus und
hole mir den Commit mit git cherry-pick
dorthin. Danach einmal
git-magic-blog
aufrufen und der doppelte Commit verschwindet
automatisch aus dem jquery-updates
-Branch.
Updates
Da der PHP-User die Blog-Dateien nur lesen darf, kann ich kein Update der Plugins über die Weboberfläche vornehmen. Stattdessen mache ich Folgendes:
- Branch
mitch
auschecken, das ist der für die Plugins. - Ich besorge mir das Plugin als .zip in der neuesten Version (in der Admin-Seite „Plugins verwalten“ über den Link „Weitere Informationen“ landet man auf der passenden Seite in Spartacus).
- Ich lösche das alte Plugin mit einem beherzten
rm -r plugins/serendipity_foo_bar
. - Ich packe das Archiv des neuen Plugins unterhalb von
plugins/
aus. - Ggf. mache ich ein
chmod -R -x+rX
auf das Plugin-Verzeichnis (vorher schaue ich einmal, wie die ausgepackten Daten aussehen). - Mit
git add plugins/
füge ich alle Änderungen in den Index hinzu. - Mit
git diff --staged
schaue ich noch einmal drüber, ob irgendetwas komisch aussieht. - Mit
git commit
und einem Kommentar wie updated plugin X to version Y checke ich die Änderung ein. - Mit dem Skript
git-magic-blog
rebase ich alles aufeinander und aktiviere wieder den „Komplettstand“ des Blogs im finalen Branchjquery-updates
.
Ein Update der Serendipity-Version selbst funktioniert genauso, nur
checke ich dann initial den Branch master
aus und beackere alle
Verzeichnisse außer plugins/
, templates_c/
und uploads/
(plugins/
ist bei ausgechecktem master
-Branch sowieso leer).
Da der PHP-User die eingeschränkten Schreibrechte hat, kann ich mir
sicher sein, dass außerhalb von templates_c/
und uploads/
im
laufenden Betrieb keine Dateien dazugekommen sind und so bei einem
Update ohne Rücksicht auf Verluste all das komplett löschen, was dann
aus dem Archiv wieder neu ausgepackt wird.
Durch das komplette löschen entferne ich auch Dateien, die in Version n enthalten waren, in Version n+1 aber nicht mehr. Wenn man die ZIPs nur über den alten Stand drüberkippt, bleiben eigentlich gelöschte Dateien erhalten.
git und äh… CVS?
Was mich bei Plugin-Updates regelmäßig stört, sind die neu
auftauchenden CSV-Unterverzeichnisse mit den jeweils drei Dateien
Entries
, Repository
und Root
. Die stecken in jedem
Verzeichnis in den Plugin-Archiven.
Es ist mir unklar, wie die dort hineinkommen, wo die Plugins doch inzwischen so wie auch s9y selbst in einem Git-Repository verwaltet werden. Da muss irgendwo noch alte Paketierungs-Infrastruktur am Werk sein. Davon habe ich Upstream bisher noch nichts erzählt, aber mal sehen, die lesen hier mit ;-)
Security
Da ich meine lokale DB-Konfiguration im Branch mitch
eingecheckt
habe, muss ich natürlich unbedingt sicherstellen, dass mein
.git/
-Verzeichnis nicht vom Webserver ausgeliefert wird, sonst leakt
mein DB-Passwort.
Dafür gibt es mehrere Möglichkeiten:
- Man kann die
.htaccess
im Wurzelverzeichnis passend editieren. - Man kann eine
git/.htaccess
anlegen, da reicht dann einDeny from all
aus. - Wenn man wie ich mit zwei Usern arbeitet, kann man dem PHP-User die
Leserechte durch ein
chmod 700 .git/
entziehen. - Oder man verschiebt alles im git-Repo in ein Unterverzeichnis
(z.B.
serendipity/
) und gibt dem Webserver nur Zugriff darauf. Dann liegt.git/
eine Ebene höher und ist nicht mehr erreichbar. - (x) all of the above
Fazit
Ich mache das wie beschrieben und es funktioniert seit Ewigkeiten
prima.
YMMV.
serendipity_sendMail()
gemacht:
s9y soll selbst keine Message-IDs erzeugen, das kann mein Mailserver
besser. Außerdem war irgendwas mit den Mailheadern komisch, ich habe
in einem implode()
eine taktische Korrektur von \n
auf \r\n
vorgenommen – das sollte ich vielleicht mal upstream zur Sprache
bringen.
onli blogging am : Linksammlung 35/2023