Wer seinen Code und seine Konfigurationsdateien nicht auf fremden Servern lagern möchte, kommt früher oder
später zum Thema Self-hosted Git. Die Gründe dafür sind vielfältig: Datenschutz, Kontrolle über die eigene
Infrastruktur, fehlende Internetverbindung im internen Netzwerk oder einfach der Wunsch, nicht von externen
Diensten abhängig zu sein. Im Homelab-Umfeld ist ein eigener Git-Server besonders wertvoll, weil dort
zahlreiche Konfigurationsdateien, Skripte und Playbooks versioniert werden wollen, die oft sensible
Informationen enthalten.
1.1 Gitea – die leichtgewichtige GitHub-Alternative
Gitea ist ein in Go geschriebener, selbst gehosteter Git-Dienst. Das Projekt entstand 2016 als Fork von Gogs
und hat sich seitdem zur bekanntesten leichtgewichtigen Git-Plattform für den Eigenbetrieb entwickelt. Die
Oberfläche erinnert bewusst an GitHub: Repositories, Issues, Pull Requests, Wikis, Releases und eine
integrierte CI/CD-Pipeline namens Gitea Actions gehören zum Funktionsumfang. Der Ressourcenbedarf ist dabei
deutlich geringer als bei GitLab – Gitea läuft problemlos auf einem Raspberry Pi oder einem kleinen VPS mit
512 MB RAM.
1.2 Forgejo – der Community-Fork
Ende 2022 wurde Forgejo als Hard-Fork von Gitea gegründet. Der Hintergrund: Die Entwicklergemeinde war
besorgt, nachdem das Unternehmen Gitea Ltd. gegründet wurde und Entscheidungen über die Projektzukunft ohne
ausreichende Community-Beteiligung getroffen wurden. Forgejo steht unter der Schirmherrschaft von
Codeberg e.V. und legt besonderen Wert auf offene Governance, Community-first-Entwicklung und eine freie
Lizenzpolitik.
Technisch sind Gitea und Forgejo weitgehend kompatibel. Forgejo hat jedoch begonnen, eigene Features zu
entwickeln, die nicht in Gitea eingeflossen sind – darunter ein erweitertes Föderations-Protokoll auf Basis
von ActivityPub (ForgeFed). Wer Wert auf Community-Kontrolle legt, greift zu Forgejo; wer ein breit
unterstütztes Projekt mit kommerzieller Backing-Option sucht, bleibt bei Gitea. Für den Homelab-Einsatz sind
beide Lösungen gleichwertig, und Migrationen zwischen den beiden Projekten sind unkompliziert möglich.
2. Installation
Der einfachste und empfehlenswerteste Weg zur Installation ist Docker Compose. Dadurch lässt sich der
Dienst reproduzierbar aufsetzen und leicht aktualisieren. Als Datenbank eignet sich PostgreSQL für den
Produktivbetrieb deutlich besser als SQLite, da es auch bei größeren Repositories und höherer Last stabil
bleibt und Concurrent Writes zuverlässig verarbeitet.
Der SSH-Port 2222 wird nach außen gemappt, damit der Standard-SSH-Port des Hosts frei bleibt. Git-Operationen
über SSH funktionieren dann mit ssh://git@git.example.com:2222/user/repo.git.
2.2 app.ini Konfiguration
Nach dem ersten Start wird die Konfigurationsdatei unter ./gitea-data/gitea/conf/app.ini
angelegt. Wichtige Parameter, die man nach dem Initial-Setup anpassen sollte:
Mit DISABLE_REGISTRATION = true verhindert man, dass sich unbekannte Nutzer selbst registrieren
können – im Homelab ist das in der Regel erwünscht. REQUIRE_SIGNIN_VIEW = true sorgt dafür, dass
Repositories ohne Login nicht einsehbar sind. Neue Benutzer können anschließend nur noch vom Administrator
über die Weboberfläche oder die API angelegt werden.
2.3 Reverse Proxy hinter Traefik
Im Homelab läuft Gitea üblicherweise hinter einem Reverse Proxy. Bei Traefik genügt es, den Container mit
entsprechenden Labels zu versehen:
Für Nginx als Reverse Proxy reicht ein einfacher Proxy-Pass-Block mit SSL-Terminierung via Let's Encrypt,
etwa über Certbot. Wichtig ist in beiden Fällen, dass in der app.ini die
ROOT_URL auf die öffentliche HTTPS-Adresse gesetzt ist, damit generierte Links korrekt sind.
3. Organisationen und Teams
Gitea und Forgejo bieten ein vollständiges Benutzer- und Berechtigungsmodell, das auch für den
Einzelnutzer im Homelab sinnvoll strukturiert werden kann. Selbst wenn man alleine arbeitet, lohnt sich
die Nutzung von Organisationen als logische Gruppierung.
3.1 Benutzer, Organisationen und Teams
Die Basiseinheit ist der einzelne Benutzer-Account. Darüber hinaus können Organisationen angelegt werden,
die mehrere Nutzer bündeln und gemeinsame Repositories verwalten. Innerhalb einer Organisation lassen sich
Teams mit granularen Berechtigungen definieren: Lesezugriff, Schreibzugriff oder Owner-Rechte für einzelne
Repositories oder für alle Repositories der Organisation. Es gibt außerdem die Möglichkeit, ein Team nur
mit Zugriff auf bestimmte Repositories auszustatten, was bei Shared-Homelabs mit mehreren Personen
praktisch ist.
3.2 Empfohlene Struktur im Homelab
Eine bewährte Vorgehensweise ist das Anlegen einer Organisation namens homelab, die alle
infrastrukturbezogenen Repositories bündelt. Innerhalb dieser Organisation empfiehlt sich folgende
Repository-Struktur:
homelab/
├── ansible/ # Ansible Playbooks und Rollen
├── docker-compose/ # Compose-Dateien pro Dienst oder Stack
├── network/ # Netzwerkkonfigurationen (Firewall, DNS, VLANs)
├── scripts/ # Shell-Skripte und Automatisierungen
├── docs/ # Dokumentation als Markdown
└── kubernetes/ # K8s-Manifeste, Helm-Charts (falls verwendet)
Durch die Organisation bleibt der persönliche Namespace sauber, und bei Bedarf können weitere Personen –
etwa Familie oder Freunde im Shared-Homelab – gezielt eingeladen werden, ohne vollen Zugriff auf alle
Repositories zu erhalten. Über Webhooks können Repositories außerdem automatisch externe Prozesse
anstoßen, sobald neue Commits gepusht werden.
4. Homelab-Nutzung
Der eigentliche Mehrwert eines selbst gehosteten Git-Servers zeigt sich im täglichen Umgang mit der
Homelab-Infrastruktur. Statt Konfigurationsdateien auf dem Server direkt zu editieren und dabei schnell den
Überblick zu verlieren, werden alle Änderungen versioniert, nachvollziehbar gemacht und bei Bedarf
rückgängig gemacht. Das Prinzip Infrastructure as Code wird damit auch im kleinen Maßstab umsetzbar.
4.1 Ansible Playbooks versionieren
Ansible-Projekte profitieren besonders von Git. Nicht nur die Playbooks selbst, sondern auch Inventories,
Variablendateien und Rollen werden im Repository gepflegt. Sensible Werte wie Passwörter oder API-Keys
sollten dabei mit Ansible Vault verschlüsselt werden, bevor sie committet werden – so ist auch der
verschlüsselte Vault-Inhalt sicher in Git versionierbar.
Ein typischer Workflow ist: Playbook lokal editieren, per git commit sichern, per
git push in Gitea hochladen und von dort aus den Gitea-Actions-Runner das Playbook automatisch
gegen das Inventory ausführen lassen. So entsteht ein vollständiger GitOps-Zyklus ohne externe Dienste.
4.2 Docker Compose Dateien
Jeder laufende Dienst im Homelab sollte seine docker-compose.yml sowie die zugehörige
.env.example-Datei (ohne echte Secrets, dafür mit Platzhaltern) im Repository haben. So lässt
sich jeder Stack auf einem neuen Server in Minuten wiederherstellen. Eine saubere Trennung zwischen der
Compose-Datei im Repository und den tatsächlichen Secrets (die lokal oder in einem Secret-Manager liegen)
ist dabei wichtig. Die .env-Datei mit echten Werten gehört in die .gitignore.
Firewall-Regeln (iptables, nftables), DNS-Zonendateien, VLAN-Konfigurationen von Switches oder
Routerkonfigurationen lassen sich als Textdateien im Repository ablegen. Auch Shell-Skripte zur
Automatisierung wiederkehrender Aufgaben – Backups, Log-Rotationen, Monitoring-Checks – gehören in Git.
Durch die Versionierung ist stets nachvollziehbar, wann welche Regeländerung vorgenommen wurde und warum.
Commit-Messages fungieren dabei als Betriebstagebuch der eigenen Infrastruktur.
4.4 Dokumentation als Markdown
Gitea und Forgejo rendern Markdown-Dateien direkt in der Weboberfläche. Das macht das Repository gleichzeitig
zur Wissensdatenbank. Netzwerkpläne, Entscheidungsprotokolle, Setup-Anleitungen und Zugangskonzepte (ohne
echte Credentials) lassen sich so direkt neben dem Code ablegen und sind über die Git-History vollständig
nachvollziehbar. Ergänzend bietet jedes Repository eine eingebaute Wiki-Funktion für umfangreichere
Dokumentation, die separat vom Code-Repository versioniert wird.
5. Mirror-Repositories
Gitea und Forgejo bieten eine praktische Mirror-Funktion, die es ermöglicht, externe Repositories
automatisch zu spiegeln oder eigene Repositories auf externe Dienste zu sichern. Das schützt vor Ausfällen
einzelner Plattformen und stellt sicher, dass wichtige Projekte jederzeit verfügbar sind.
5.1 Pull-Mirror: externe Repos einbinden
Über die Repository-Einstellungen kann ein Pull-Mirror eingerichtet werden. Gitea überprüft dann in einem
konfigurierbaren Intervall (zum Beispiel alle 8 Stunden) das Quell-Repository auf GitHub oder GitLab und
synchronisiert alle Branches, Tags und Commits. Das ist nützlich, um externe Abhängigkeiten oder
interessante Open-Source-Projekte lokal verfügbar zu halten, auch wenn die externe Plattform einmal nicht
erreichbar ist oder ein Repository unerwartet gelöscht wird.
# Einrichten eines Pull-Mirrors über die API
curl -X POST "https://git.example.com/api/v1/repos/migrate" \
-H "Authorization: token DEIN_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clone_addr": "https://github.com/owner/repo",
"repo_name": "repo",
"mirror": true,
"mirror_interval": "8h0m0s",
"private": true,
"uid": 1
}'
5.2 Push-Mirror: Backup auf externen Server
Push-Mirrors funktionieren in die entgegengesetzte Richtung: Jeder Push in das lokale Gitea-Repository wird
automatisch an ein externes Repository weitergeleitet. Das eignet sich hervorragend als Backup-Strategie –
alle Homelab-Repositories werden zusätzlich auf GitHub oder einem zweiten Gitea-Server gespiegelt. Die
Push-Mirror-Konfiguration erfolgt über die Repository-Einstellungen unter dem Punkt "Git Hooks / Mirrors".
Wichtig ist, dass für private GitHub-Repositories ein Personal Access Token mit repo-Scope
verwendet wird. So entsteht eine Offsite-Kopie aller Repositories, ohne dass dafür ein separater
Backup-Prozess eingerichtet werden muss.
6. Gitea Actions / Forgejo Actions
Seit Gitea 1.19 ist eine integrierte CI/CD-Pipeline verfügbar: Gitea Actions. Forgejo hat diese Funktion
übernommen und weiterentwickelt. Die Workflow-Syntax ist bewusst kompatibel zu GitHub Actions gehalten,
was eine Migration und Wiederverwendung von bestehenden Workflows erleichtert. Wer bereits GitHub Actions
kennt, findet sich sofort zurecht.
6.1 Runner-Setup
Für die Ausführung von Workflows wird ein separater Act-Runner benötigt. Dieser kann ebenfalls per Docker
Compose auf demselben oder einem anderen Host betrieben werden:
Das Registrierungs-Token wird in der Gitea-Weboberfläche unter Site Administration → Runners erzeugt.
Der Runner registriert sich beim Start automatisch und ist danach bereit, Jobs entgegenzunehmen. Über den
Docker-Socket kann der Runner eigene Docker-Container für die Job-Ausführung starten, was die übliche
Vorgehensweise für isolierte Build-Umgebungen ist.
6.2 Einfacher Workflow: Ansible Lint
Ein typischer Anwendungsfall ist der automatische Syntax-Check für Ansible Playbooks bei jedem Push.
Die Workflow-Datei liegt im Repository unter .gitea/workflows/lint.yml:
name: Ansible Lint
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install ansible-lint
run: pip install ansible-lint
- name: Run ansible-lint
run: ansible-lint playbooks/
6.3 Deployment-Trigger
Ein weiterer nützlicher Workflow ist ein automatischer Deployment-Trigger: Sobald ein Tag mit dem Muster
v* gepusht wird, verbindet sich der Runner per SSH auf den Zielserver und führt ein
docker compose pull && docker compose up -d aus. So wird aus einem einfachen
git tag v1.2 && git push --tags ein vollständiger Deployment-Vorgang ohne manuelle
Serveranmeldung. Der SSH-Schlüssel wird dabei als verschlüsseltes Secret in den Repository-Einstellungen
hinterlegt und ist für Workflow-Jobs über die Umgebungsvariable secrets.DEPLOY_KEY abrufbar.
7. Backup und Migration
Auch der eigene Git-Server muss regelmäßig gesichert werden. Gitea und Forgejo bieten dafür einen
integrierten Backup-Mechanismus sowie klare Strukturen für manuelle Sicherungen. Ein Ausfall ohne Backup
würde den Verlust der gesamten versionierten Infrastrukturhistorie bedeuten.
7.1 Gitea-internes Backup
Der eingebaute Backup-Befehl erzeugt ein vollständiges Archiv aller relevanten Daten – Datenbank,
Konfiguration, Repository-Daten, Attachments und Avatare:
# Backup innerhalb des Containers ausführen
docker exec -u git gitea gitea dump \
-c /data/gitea/conf/app.ini \
--file /data/gitea-backup-$(date +%Y%m%d).zip
# Backup aus dem Container auf den Host kopieren
docker cp gitea:/data/gitea-backup-$(date +%Y%m%d).zip ./backups/
Das erzeugte ZIP-Archiv enthält alle notwendigen Daten für eine vollständige Wiederherstellung auf einem
neuen System. Es empfiehlt sich, diesen Befehl als Cron-Job täglich auszuführen und die resultierenden
Archive auf einen externen Speicher (NAS, S3-kompatibel) zu übertragen.
7.2 Datenbank-Backup
Das Gitea-Dump-Kommando enthält bei SQLite die Datenbankdatei direkt im Archiv. Bei PostgreSQL empfiehlt
sich zusätzlich ein separates Datenbank-Dump, das unabhängig vom Gitea-Prozess erstellt werden kann und
auch für Point-in-Time-Recovery nutzbar ist:
Die eigentlichen Git-Repositories liegen im Volume unter ./gitea-data/gitea/repositories/.
Diese können direkt per rsync oder restic auf einen externen Speicher gesichert werden. Da es sich um
bare Git-Repositories handelt, sind sie problemlos kopier- und wiederherstellbar. In Kombination mit den
Push-Mirrors aus Abschnitt 5 ergibt sich eine zweistufige Backup-Strategie: lokales Volume-Backup plus
Offsite-Spiegel auf GitHub oder einem zweiten Gitea-Server.
# Inkrementelles Backup mit restic auf ein NAS
restic -r sftp:user@nas.local:/backups/gitea backup \
./gitea-data/gitea/repositories \
./gitea-data/gitea/conf \
./backups/
7.4 Migration von GitHub zu Gitea
Die einfachste Migrationsmethode ist die eingebaute Migrate-Funktion in der Weboberfläche. Unter
"New Migration" kann als Quelle GitHub angegeben werden. Gitea importiert dabei nicht nur den
Repository-Inhalt, sondern auch Issues, Labels, Milestones, Pull Requests, Releases und Wiki-Seiten –
sofern ein GitHub-Token mit den entsprechenden Leserechten angegeben wird.
# Massenimport mehrerer Repositories über die Gitea API
for repo in repo1 repo2 repo3; do
curl -X POST "https://git.example.com/api/v1/repos/migrate" \
-H "Authorization: token GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"clone_addr\": \"https://github.com/username/${repo}\",
\"auth_token\": \"GITHUB_TOKEN\",
\"repo_name\": \"${repo}\",
\"issues\": true,
\"labels\": true,
\"milestones\": true,
\"pull_requests\": true,
\"releases\": true,
\"wiki\": true,
\"private\": true,
\"uid\": 1
}"
done
Nach der Migration empfiehlt es sich, in den GitHub-Repository-Einstellungen eine Archivierung
vorzunehmen, damit bestehende Klone und Links weiterhin funktionieren. Für den dauerhaften Betrieb
sollten in lokalen Git-Konfigurationen die Remote-URLs von GitHub auf die neue Gitea-Instanz
umgestellt werden:
# Remote-URL eines bestehenden lokalen Repositories umstellen
git remote set-url origin https://git.example.com/homelab/repo.git
# Alle Remotes des Repositories prüfen
git remote -v
Mit Gitea oder Forgejo hat man eine vollständige, selbst kontrollierte Git-Plattform, die keine
Wünsche offenlässt: von der einfachen Versionierung einzelner Konfigurationsdateien über strukturierte
Organisations- und Berechtigungsmodelle bis hin zu vollständigen CI/CD-Pipelines. Im Homelab ist ein
solcher Git-Server nicht nur nützlich, sondern nach kurzer Eingewöhnung schlicht unverzichtbar – er bildet
das Fundament für jede Form von Infrastructure as Code.