Git auf dem Webserver einrichten und Inhalte automatisch aktualisieren

Veröffentlicht am Dienstag, den 21. Februar 2023

Einführung

Anfangs habe ich FTP verwendet, um Dateien auf den Server hochzuladen und schon vorhandene zu aktualisieren. Aber was ist, wenn es kein Internet gibt, um die Dateien zu bearbeiten? Wie halte ich eine lokale Kopie des Servers auf meinem Rechner aktuell mit meinem Server?

Mit Git kann man diese Probleme sehr einfach lösen. Git ist ein Versionskontrollsystem auf Englisch Version Control System (VCS) genannt, welches ermöglicht Dateien zu tracken und Änderungen aufzuzeichnen. Eine wesentliche Stärke von Git gegenüber anderen VCS ist, dass die Einrichtung auf einem Server sehr einfach ist und man nur mit dem Server kommuniziert, wenn man es explizit befehlt (z.B. bei Änderungen). Man behält eine Kopie vom kompletten Änderungsbaum lokal und bearbeitet seine Dateien lokal. Sobald man mit den Änderungen fertig ist, 'committet' man und 'pusht' die Dateien auf den Server hoch. Wie man das nun einrichtet, zeige ich hier.

Ein grundlegendes Verständnis, wie Git funktioniert (add, commit, push), hilft beim Ausführen der Befehle. Auch zu wiessen, wie man die Konsole verwendet (cd, mkdir, rm), schadet nicht. Zu jedem Teil habe ich die Inputs und Outputs der Konsole hinzugefügt, damit man vergleichen kann. Von daher ist es nicht schlimm, wenn vieles neu ist. Man lernt durch ausprobieren.

Schritt 1: Zugang zum Server über SSH

Man braucht für diese Methode einen Zugang zum Webserver mittels SSH. Webhosting-Provider machen das immer unterschiedlich und ich bin derzeit bei Manitu gehostet. Somit wird es für jeden unterschiedlich sein. Bei Manitu richtet man das über die Weboberfläche ein, was in der Einrichtung SSH-Benutzer einfach beschrieben wird. Ich habe zusätzlich in ~/.ssh eine config Datei erstellt, die einen Alias für meinen Server erstellt:

Host manitu 
HostName XXX.manitu.net
IdentityFile ~/.ssh/id_XXX
User XXX
config Datei in ~/.zsh

Hier sollte man XXX mit den relevanten Daten ersetzen. Bei HostName sollte also sowas stehen, wie ngcobalt.manitu.net. Die IdentityFile ist der Ort, an dem der private SSH-Schlüssel liegt und für die Anmeldung über SSH verwendet werden soll. Sowas wie id_rsa steht dann dort. Bei User dann der ssh-Benutzername. Man sollte seinen privaten Schlüssel (z.B. id_rsa) nur für sich behalten und nie teilen!

Damit kann man einfach ssh manitu eingeben und das System weiß direkt, welche Adresse, welcher Hostname und welcher Schlüssel verwendet werden soll. Kurz ausprobieren, bevor man zum nächsten Schritt geht.

Konsole: SSH Schlüssel erzeugen
user ~ % ssh-keygen -t ed25519 -C "Webserver"    
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/user/.ssh/id_ed25519): #ENTER DRÜCKEN
Enter passphrase (empty for no passphrase): #OPTIONALES PASSWORT SETZEN; EMPFOHLEN
Enter same passphrase again: 
Your identification has been saved in /Users/user/.ssh/id_ed25519
Your public key has been saved in /Users/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:EV6bjwGIHK+DGek0vpyNF3iZD6gzJepgogS/Xrnydcs Webserver
The key's randomart image is:
+--[ED25519 256]--+
|   ..o .o .      |
|   .o... + o     |
|  =   . o +      |
| + B +   . +     |
|o O O   S . .    |
|o* * *           |
|Bo* = o .        |
|Bo.+ o o .       |
|.oooo   E        |
+----[SHA256]-----+

user ~ % cat /Users/user/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPxbSTq1Z+WD/2dHyJRqHh6reLjTDBf0FMM0Gda6E0Cf Webserver
SSH Schlüssel in der Konsole erzeugen
Konsole: Alias erzeugen
nano ~/.ssh/config #Datei erstellen und Inhalt (siehe oben) speichern.
Alias in der Konsole erzeugen
Konsole: SSH zum Server
user ~ % ssh manitu
Mit dem Server über SSH in der Konsole verbinden

Schritt 2: Git auf dem Server einrichten

Die Git-Dokumentation beschreibt sehr gut, wie man Git auf dem Server einrichtet und daran orientieren wir uns hier. Falls du schon Daten auf dem Webserver hast und diese mit Git ab sofort verwalten möchtest, springe zu Falls Dateien schon auf dem Server sind.

Wir erstellen auf dem Server ein Verzeichnis /srv/git/web.git/, wobei dieses Verzeichnis im Root-Directory des Servers drinsteht, also NICHT im Verzeichnis, wo der Webserver die Inhalte per HTTP (HyperText Transfer Protocol) liefert. Normalerweise heißt dieses Verzeichnis web oder htdocs. Man möchte nämlich aus Sicherheitsgründen vermeiden, dass das gesamte Git-Repository von Außen frei zugänglich ist. Damit umgeht man dieses Problem komplett.

In diesem Verzeichnis /srv/git/web.git/ erstellen wir ein leeres Git-Repository mit dem Befehl git init --bare --shared. Der Flag --bare bedeutet bloß, dass kein Arbeitsverzeichnis erstellt werden soll. Der Flag --shared fügt Schreibrechte für Gruppen hinzu.

Konsole: Einrichtung Git auf Server
server ~ % git init --bare --shared /srv/git/web.git/ 
Initialized empty shared Git repository in <#PFAD>/srv/git/web.git/
Leeres Git Repository auf dem Server

Falls Dateien schon auf dem Server sind

Hier würde ich zuerst alle bestehenden Dateien kopieren und irgendwo ablegen z.B. auf dem Computer, bevor man irgendetwas macht. Mit der Kopie kann man dann sicher arbeiten. Erstelle also ein Verzeichnis, dass diese Dateien enthält. Der Name des Ordners kann web sein. Gehe zu diesem Ordner in der Konsole mit cd <#PFAD>/<#NAME>/ und gebe den folgenden Befehl ein: git init, gefolgt von git add . und git commit -m "Initial". Sobald das fertig ist, gehe nun ein Verzeichnis wieder hoch: cd ... Dort gibst du dann git clone --bare --shared web web.git .

Nachdem das Repository web.git erstellt wurde, lädst du das Repository auf den Server beim Pfad /srv/git/ hoch. Den Ordner web.git, den du vorhin auf dem Computer erstellt hast, brauchst du nun nicht mehr und kannst den löschen. Behalte aber den Ordner web, das spart gleich ein paar Schritte.

Konsole: Einrichtung Git bei vorhandenen Daten
user ~ % cd web 

user web % git init
Initialized empty Git repository in <#PFAD>/web/.git/

user web % git add .

user web % git commit -m "Initial"
[main (root-commit) 6f37be7] Initial
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.html

user web % cd ..

user ~ % git clone --bare --shared web web.git
Cloning into bare repository 'web.git'...
done.
Befehle für die Einrichtung eines nicht-leeren Repositories

Schritt 3: Git auf dem Client einrichten

Falls du schon aus Schritt 2 Dateien vom Server kopiert hast, dann springe zu Falls man das lokale Repository schon eingerichtet hat.

Die Verbindung zwischen Server und Client soll nun über Git hergestellt werden. Zuerst navigieren wir auf dem Rechner dahin, wo man in Zukunft die Dateien ablegen möchte. Wir fügen die Verbindung mit git clone ssh://manitu/srv/git/web.git/ hinzu. Achtung: Hier kann der Pfad anders sein, als hier angegeben. Man sollte überprüfen, welcher Pfad konkret von der Wurzel / bis zu web.git führt. Der in der config Datei eingegebene Alias ermöglicht eine einfach Verbindung zum Server, indem nur manitu angegeben wird. Git hat nun einen leeren Ordner web erstellt und die Verbindung zwischen Server und Client sollte erfolgreich gewesen sein. Man kann jetzt anfangen, Dateien und Ordner zu erstellen und die Website ins Leben zu rufen!

Sobald man mit allen Änderungen fertig ist und 'committet' hat, gibt man nun git push origin main ein und lädt die Änderungen auf den Server hoch.

Konsole: Git auf dem Client einrichten
user ~ % git clone ssh://manitu/srv/git/web.git
Cloning into 'web'...
remote: Objekte aufzählen: 136, fertig.
remote: Zähle Objekte: 100% (136/136), fertig.
remote: Komprimiere Objekte: 100% (134/134), fertig.
remote: Gesamt 136 (Delta 64), Wiederverwendet 0 (Delta 0), Pack wiederverwendet 0
Receiving objects: 100% (136/136), 937.77 KiB | 2.67 MiB/s, done.
Resolving deltas: 100% (64/64), done.

# Dateien erstellen, bearbeiten...

user web % git add <DATEIEN>

user web % git commit -m "<NACHRICHT>"
[main b8b0334] "<NACHRICHT>"
 1 file changed, 1 insertion(+), 1 deletion(-)

user web % git push origin main
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To ../web.git
   a11ad3c..b8b0334  main -> main
Git auf dem Client in der Konsole einrichten

Falls man das lokale Repository schon eingerichtet hat

Hier ist das lokale Repository schon aus Schritt 2 auf dem Rechner. Man geht in den Ordner web und führt den Befehl git remote add origin ssh://manitu/srv/git/web.git/ aus. Achtung: Hier kann der Pfad anders sein, als hier angegeben. Man sollte überprüfen, welcher Pfad konkret von der Wurzel / bis zu web.git führt. Der in der config Datei eingegebene Alias ermöglicht eine einfach Verbindung zum Server, indem nur manitu angegeben wird. Die Verbindung zwischen Server und Client sollte erfolgreich gewesen sein.

Sobald man mit allen Änderungen fertig ist und 'committet' hat, gibt man nun git push origin main ein und lädt die Änderungen auf den Server hoch.

Konsole: Git Remote hinzufügen
user web % git remote add origin ssh://manitu/srv/git/web.git/
Git Remote in der Konsole hinzufügen

Schritt 4: Änderungen auf dem Server in die Website einspielen

Nachdem man vom Rechner gepusht hat, sieht man auf dem Server erstmal garnichts davon. Es hat sich nichts geändert. Wieso?

Da wir ein bare Repository erstellt haben, gibt es kein Arbeitsverzeichnis bei web.git. Das bedeutet, dass alle Änderungen und alle Git-Branches sicher abgespeichert sind, bloß gibt es direkt für den Benutzer keine Dateien zu sehen. Da man ohnehin lokal arbeitet, wurde genau diese Option für Server entworfen, damit die Dateien nicht unnötig auf dem Server liegen, obwohl sie dort keiner braucht.

Man kann sich diese Dateien aber ausgeben lassen. Das machen wir mit Git Hooks, um benutzerdefinierte Skripte laufen zu lassen. Im Server gehen wir zu /srv/git/web.git/hooks/ und erstellen eine Datei namens post-receive. In dieser Datei geben wir folgendes ein:

#! /bin/zsh
GIT_WORK_TREE=/web/ git checkout -fq main
post-receive Datei in /srv/git/web.git/hooks/

Mein Webserver nutzt hier zsh. Falls dein Server etwas anderes benutzt, z.B. bash, dann musst du das ersetzen.

Damit man keine Probleme mit Schreibrechten bekommt, sollte man schon vorhandene betroffene Dateien einmal löschen, damit das System diese Dateien nochmal selbst erstellt. Ich hatte dieses Problem und zuerst alle Daten gesichert, falls etwas schief gehen sollte. Ich habe dann meinen kompletten web-Ordner gelöscht und die Dateien nochmal drauf gepusht. Bevor man Daten löscht, sollte man aber davor immer sicher gehen, dass man eine Kopie an eine ANDERE Stelle aufbewahrt!

Dieses Skript kopiert den Inhalt des main-Branches in die nun eingeführte GIT_WORK_TREE, also ein gewähltes Arbeitsverzeichnis. Hier sollte der Pfad so angepasst werden, dass das Verzeichnis, das für die angezeigten Webinhalte im Browser zuständig ist, auch hier hingeschrieben wird.

Dieses Skript muss nun vom System ausführbar gemacht werden. Dazu gibt man folgenden Befehl ein chmod +x post-receive, wobei man hier in dem hooks Ordner sein sollte.

Man kann nun seine Änderungen lokal vom Rechner auf den Server pushen und der Server erledigt den Rest, um die Dateien an die richtige Stelle zu kopieren und die Website zu aktualisieren!

Konsole: Git Hooks einrichten
user ~ % cd /srv/git/web.git/hooks/
user hooks % nano post-receive #Datei erstellen und Inhalt (siehe oben) speichern.
user hooks % chmod +x post-receive
Git Hook post-receive in der Konsole einrichten

OPTIONAL: Github verwenden

Möchte man die Dateien auch auf Github in einem privaten Repository hochladen, dann geht das sehr einfach. Folgt man der offiziellen Dokumentation von Github, um Repositories zu erstellen, dann muss man nur noch in seiner lokalen Repository ein weiteres Remote hinzufügen: git remote add github <#GITHUB-ADRESSE>.

Jetzt kann man auch auf GitHub Änderungen hochladen, indem man git push github main eingibt. GitHub ist kein Backup-Service und man sollte sich nicht als Solches darauf verlassen, aber die Wahrscheinlichkeit, dass GitHub Daten verliert sollte sehr gering sein.

Konsole: Github einrichten
user web % git remote add github <#GITHUB-ADRESSE>
Github in der Konsole einrichten

Kleine Extras

Falls man eine .gitignore Datei verwendet, kann man diese in dem web-Ordner wieder löschen, da sie nicht auf dem Server gebraucht wird. Man fügt das hier in die post-receive Datei unter dem Git Befehl hinzu:

cd /web/
rm .gitignore
post-receive Datei in /srv/git/web.git/hooks/ ergänzt

Wenn man möchte, kann man mehr als nur den Webauftritt mit Git tracken. Template-Dateien und Ähnliches gehören nicht direkt zum Webauftritt, sind aber trotzdem relevant für den Server. Man bewegt lokal alle Dateien des Reposiories in einen Ordner web und erstellt einen weiteren Ordner helper beispielsweise. Im helper Ordner fügt man dann die Dateien hinzu, die auf dem Webserver gespeichert werden, aber nicht über den Browser erreichbar sein sollen. Dann passt man die post-receive Datei an, indem man das Verzeichnis bei GIT_WORK_TREE=/web/ mit / ersetzt.

Weiterführende Links

Ab sofort sollte alles wie gewollt funktionieren! Als ich die Änderungen zum ersten mal im Browser sah, war ich erstaunt, wie einfach Git zu benutzen und wie mächtig es ist. Das Buch Pro Git ist wirklich sehr gut geschrieben, offiziell von Gitbetreibern herausgegeben und kostenlos. Ich kann es definitiv empfehlen.

Ich habe mit folgenden Quellen gearbeitet, um alles einzurichten:

Falls also etwas nicht klappen sollte, würde ich empfehlen dort zu schauen.