Forgejo: der eigene Git-Server hinter Traefik
Forgejo mit Docker & Traefik aufsetzen: eigener Git-Server mit HTTPS, Repos per Web-UI, Klonen über HTTPS und SSH – die selbstgehostete GitHub-Alternative.
Inhaltsverzeichnis
GitHub ist bequem – aber dein Code liegt dann auf fremden Servern. Mit Forgejo hostest du deine Repositories selbst: eine schlanke, komplett quelloffene Git-Plattform, die auf dem kleinsten VPS läuft und trotzdem Issues, Pull-Requests, Wiki und CI mitbringt.
Was bauen wir?
Am Ende läuft Forgejo 16.0.3 als einzelner Container hinter deinem Traefik, erreichbar unter
https://DEINE_DOMAIN mit automatischem Let’s-Encrypt-Zertifikat. Du legst Repositories über die
Web-Oberfläche an und klonst/pushst sie wahlweise über HTTPS oder über SSH. Als Datenbank
nutzen wir SQLite – für einen persönlichen oder kleinen Team-Git-Server reicht das locker und
spart einen zusätzlichen Datenbank-Container. Forgejo ist der Community-Fork von Gitea und in der
Selfhosting-Szene klar im Aufwind.
Warum überhaupt selbst hosten? Dein Code, deine Issues und dein Projektverlauf liegen dann ausschließlich auf deinem Server – keine Abhängigkeit von den Konditionen, Rate-Limits oder Übernahmen eines externen Anbieters, und volle Datenhoheit. Forgejo ist dabei kein abgespecktes Spielzeug: Es kann fast alles, was du von GitHub kennst (siehe Schritt 7), bleibt aber schlank genug für einen kleinen VPS.
Voraussetzungen
- Ein Server mit Debian 13 und laufendem Docker (getestet auf einem netcup VPS).
- Ein Reverse Proxy mit Traefik (das
proxy-Netz und der Resolverledaraus werden vorausgesetzt) – Forgejo bringt kein eigenes HTTPS mit, Traefik übernimmt die Verschlüsselung. - Eine (Sub-)Domain, die per A-/AAAA-Record auf deinen Server zeigt (
DEINE_DOMAIN). - Für echte Backups: verschlüsselte Backups mit Restic.
Forgejo ist genügsam und läuft schon auf dem kleinsten vServer. Wie viel Server dein geplantes Setup insgesamt braucht, schätzt dir der Server-Rechner.
VPS 1000 G12
4 vCore · 8 GB RAM · 256 GB NVMe
ab 10,36 €/Monat
Forgejo mit SQLite läuft entspannt auf dem VPS 1000.
💶 5 € Gutschein für netcup-Neukunden:36nc17844976032
(nur Neukunden, keine Domains)
Schritt für Schritt
Schritt 1: Compose-Datei anlegen
Lege einen Ordner für den Stack an und wechsle hinein:
mkdir -p /opt/forgejo && cd /opt/forgejoErstelle die Datei compose.yaml. Ersetze DEINE_DOMAIN durch deine echte Domain:
services:
forgejo:
image: codeberg.org/forgejo/forgejo:16.0.3
container_name: forgejo
restart: unless-stopped
environment:
USER_UID: 1000
USER_GID: 1000
FORGEJO__server__DOMAIN: DEINE_DOMAIN
FORGEJO__server__ROOT_URL: https://DEINE_DOMAIN/
FORGEJO__server__SSH_DOMAIN: DEINE_DOMAIN
FORGEJO__server__START_SSH_SERVER: "true"
FORGEJO__server__SSH_PORT: "2222"
FORGEJO__server__SSH_LISTEN_PORT: "2222"
FORGEJO__service__DISABLE_REGISTRATION: "true"
FORGEJO__database__DB_TYPE: sqlite3
volumes:
- forgejo_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "2222:2222"
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:3000/api/healthz"]
start_period: 30s
start_interval: 2s
interval: 30s
timeout: 5s
retries: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.forgejo.rule=Host(`DEINE_DOMAIN`)"
- "traefik.http.routers.forgejo.entrypoints=websecure"
- "traefik.http.routers.forgejo.tls.certresolver=le"
- "traefik.http.services.forgejo.loadbalancer.server.port=3000"
networks: [proxy]
volumes:
forgejo_data: {}
networks:
proxy:
external: trueDie wichtigsten Stellen im Detail:
FORGEJO__…-Variablen konfigurieren Forgejo direkt über Umgebungsvariablen (Abschnitt und Schlüssel per doppeltem Unterstrich).ROOT_URLmuss exakt die öffentliche HTTPS-Adresse sein, sonst zeigen Klon-Links und Weiterleitungen ins Leere.- Git über SSH übernimmt Forgejos eingebauter SSH-Server (
START_SSH_SERVER=true) – so musst du den gehärteten SSH-Zugang deines Hosts (Port 22) nicht anfassen. Er lauscht im Container auf 2222 und wird auf denselben Host-Port veröffentlicht. loadbalancer.server.port=3000sagt Traefik, dass die Weboberfläche intern auf Port 3000 läuft. Nur SSH (2222) wird direkt als Port veröffentlicht – der Web-Zugriff geht ausschließlich über Traefik.- Der Healthcheck mit
start_interval: 2sist bewusst so gesetzt (mehr dazu in „Wenn es nicht funktioniert"). DISABLE_REGISTRATION: "true"schließt die offene Selbst-Registrierung von Anfang an – dein Git-Server steht damit nicht für Fremde offen. Dein Admin-Konto legst du trotzdem ganz normal im Erstinstallations-Wizard an (Schritt 3); alternativ könntest du es überFORGEJO__admin__*-Variablen automatisiert erzeugen.
SSH-Port: unbedingt beide Werte setzen
SSH_PORT (die im Klon-Link angezeigte Portnummer) und SSH_LISTEN_PORT (der Port, auf dem der
Server tatsächlich lauscht) müssen zusammenpassen. Setzt du nur SSH_PORT und lässt SSH_LISTEN_PORT
weg, versucht Forgejo auf dem alten Standard-Port zu lauschen und stürzt beim Start mit
bind: address already in use in eine Neustart-Schleife.Schritt 2: Starten und auf „healthy" warten
Starte den Container:
docker compose up -dPrüfe den Status:
docker compose psNach wenigen Sekunden steht der Container auf healthy:
NAME IMAGE SERVICE STATUS PORTS
forgejo codeberg.org/forgejo/forgejo:16.0.3 forgejo Up 12 seconds (healthy) 22/tcp, 3000/tcp, 0.0.0.0:2222->2222/tcp, [::]:2222->2222/tcpDas 22/tcp in der Portliste ist nur ein vom Image deklarierter Port ohne Veröffentlichung – nach
außen erreichbar ist ausschließlich der 2222er, den du selbst gemappt hast.
Traefik holt jetzt im Hintergrund das Zertifikat. Prüfe von deinem Rechner aus, dass die Weboberfläche über HTTPS antwortet:
curl -s https://DEINE_DOMAIN/api/healthzErwartete Ausgabe – Forgejo meldet sich gesund. Solange die Erstinstallation (Schritt 3) noch nicht durch ist, antwortet der Endpunkt knapp mit Status und Slogan:
{
"status": "pass",
"description": "Forgejo: Beyond coding. We forge."
}Nach dem Abschluss des Wizards listet dieselbe URL zusätzlich die Einzelprüfungen cache:ping und
database:ping auf – dann steht dort auch dein Instanzname statt des Slogans.
Schritt 3: Erstinstallation & Admin-Konto
Rufe https://DEINE_DOMAIN im Browser auf. Beim ersten Start zeigt Forgejo die Erstinstallation.
Die Datenbank- und Server-Einstellungen sind dank der Umgebungsvariablen bereits korrekt vorbelegt –
du musst hier nur noch das Administrator-Konto anlegen (klapp den entsprechenden Abschnitt auf und
trage Benutzername, E-Mail und ein starkes Passwort ein). Ein Klick auf Forgejo installieren, und
nach einem kurzen Neustart landest du auf deinem leeren Dashboard:

Tipp
docker compose up -d ab und lege dabei dein Admin-Konto an. Die offene
Selbst-Registrierung ist bereits über FORGEJO__service__DISABLE_REGISTRATION: "true" in der Compose
deaktiviert, sodass sich niemand von außen ein Konto anlegen kann.Schritt 4: Erstes Repository anlegen
Klicke oben rechts auf das + und dann auf Neues Repository. Vergib einen Namen und setze den
Haken bei Repository initialisieren (legt direkt eine README an, damit das Repo nicht leer ist):

Nach dem Anlegen siehst du die Repository-Ansicht. Über den Umschalter HTTPS / SSH bekommst du die passende Klon-Adresse:

Schritt 5: Klonen und pushen über HTTPS
Am schnellsten geht es über HTTPS – es funktioniert sofort, ohne Schlüssel einzurichten:
git clone https://DEINE_DOMAIN/DEIN_BENUTZER/mein-erstes-repo.gitEin öffentliches Repository klonst du ohne Anmeldung – erwartete Ausgabe:
Cloning into 'mein-erstes-repo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (3/3), done.Bei einem privaten Repository fragt Git schon hier nach Benutzername und Passwort. Damit ist der Kreis geschlossen – du legst eine Datei an, committest sie und schiebst sie zurück auf deinen Server:
cd mein-erstes-repo
echo "Meine erste Notiz" >> notizen.txt
git add notizen.txt
git commit -m "Erste Notiz"
git pushSpätestens beim git push will Forgejo wissen, wer du bist: Git fragt nach Benutzername und Passwort.
Am Ende bestätigt Git den neuen Stand auf dem Server:
To https://DEINE_DOMAIN/DEIN_BENUTZER/mein-erstes-repo.git
f398f79..7bad57b main -> mainTipp
Please tell me who you are, solange Git
deinen Namen und deine E-Mail nicht kennt. Setze sie einmalig global:
git config --global user.name "DEIN NAME" und git config --global user.email "DEINE_MAIL".Sekunden später taucht der Commit in der Weboberfläche auf – dein Code liegt jetzt versioniert auf deinem eigenen Server.
Tipp
Schritt 6: Klonen und pushen über SSH
Für den täglichen Gebrauch ist SSH bequemer (kein Passwort pro Push). Hinterlege dazu deinen öffentlichen SSH-Schlüssel unter Einstellungen → SSH- / GPG-Schlüssel → Schlüssel hinzufügen:

Deinen öffentlichen Schlüssel zeigst du dir lokal mit cat ~/.ssh/id_ed25519.pub an (falls noch keiner
existiert: ssh-keygen -t ed25519). Danach klonst du über SSH – beachte den Port 2222:
git clone ssh://git@DEINE_DOMAIN:2222/DEIN_BENUTZER/mein-erstes-repo.gitDamit das klappt, muss der SSH-Port in beiden Firewalls offen sein – in der
UFW-Firewall (ufw allow 2222/tcp) und, falls genutzt, in der
netcup-Firewall.
Schritt 7: Mehr als nur Git-Hosting
Ein Repository und Klonen sind erst der Anfang – Forgejo bringt die komplette Werkbank drumherum mit. Diese Funktionen findest du in der Navigationsleiste jedes Repositories bzw. deines Kontos:
- Issues & Pull-Requests: vollwertiges Ticket-System und Code-Review inklusive Labels, Meilensteinen und Zuweisungen – die Basis für Zusammenarbeit im Team.
- Forgejo Actions: eine zu GitHub Actions kompatible CI/CD-Engine. Bestehende
.github/workflows-Dateien laufen oft ohne Änderung. Actions brauchen allerdings einen separaten Runner, der die Jobs ausführt – der gehört aus Sicherheitsgründen nicht auf den Produktiv-Host und hat ein eigenes Tutorial: Forgejo Actions: eigener CI/CD-Runner mit Docker (führt dedizierte Kerne vor: ein guter Anlass für einen Root-Server, siehe netcup-Empfehlung). - Wiki & Releases: Dokumentation direkt am Projekt und versionierte Release-Downloads.
- Paket-Registry: Forgejo kann Container-Images, npm-, Maven-, PyPI- und weitere Pakete hosten – praktisch, wenn du eigene Artefakte ablegen willst, ohne einen weiteren Dienst zu betreiben.
- Organisationen & Teams: bündele Repositories und steuere Zugriffsrechte pro Team.
Du musst deine Projekte auch nicht von Hand umziehen: Über + → Migration importiert Forgejo ein bestehendes Repository von GitHub, GitLab oder einer anderen Forgejo-/Gitea-Instanz – inklusive Issues, Pull-Requests und Releases, nicht nur der Git-Historie. So wechselst du in wenigen Minuten von GitHub auf deinen eigenen Server, ohne etwas zu verlieren.
Wenn es nicht funktioniert
Der Container startet immer wieder neu (Restarting), im Log steht bind: address already in use.
Der eingebaute SSH-Server kollidiert mit sich selbst, weil SSH_PORT und SSH_LISTEN_PORT nicht
zusammenpassen. Setze beide auf denselben Wert (hier 2222) – dann startet Forgejo sauber.
Der Container braucht ewig, bis er healthy ist. Docker führt den ersten Healthcheck standardmäßig
erst nach dem interval (30 s) aus – der Container sieht also 30 s+ „ungesund" aus, obwohl Forgejo
längst in ~2 s bereit ist. Die Lösung steckt schon oben in der Compose: start_interval: 2s prüft
während der Startphase im 2-Sekunden-Takt und schaltet sofort auf healthy, sobald die App antwortet.
(Braucht Docker 25+ / Compose v2.20+ – auf Debian 13 gegeben.)
Traefik liefert 502 Bad Gateway. Fast immer der falsche Port: Forgejos Weboberfläche lauscht intern
auf 3000, deshalb muss loadbalancer.server.port=3000 gesetzt sein und der Container im
proxy-Netz hängen.
Klon-Links zeigen localhost oder den falschen Port. Dann stimmen ROOT_URL, SSH_DOMAIN oder
SSH_PORT nicht. Korrigiere die Werte in der Compose und starte mit docker compose up -d neu.
SSH-Klon scheitert mit Permission denied (publickey). Der SSH-Server läuft, aber dein
öffentlicher Schlüssel ist noch nicht im Konto hinterlegt (Schritt 6) – oder du hast den Port 2222
vergessen.
Wartung & Backups
Alles liegt im Volume forgejo_data (/data): die SQLite-Datenbank, deine Repositories und die
Host-Keys des SSH-Servers. Genau dieses Volume gehört gesichert – am saubersten mit
restic. Weil eine SQLite-Datei im Betrieb beschrieben wird, sicherst
du sie konsistent, indem du entweder den Container kurz stoppst (docker compose stop) oder Forgejos
eingebauten Dump nutzt:
docker compose exec -u git forgejo forgejo dump -t /tmp -f /tmp/forgejo-dump.zip-u git lässt den Dump als git-Benutzer statt als root laufen (als root verweigert Forgejo den
Dump). Nach /tmp statt /data, weil das git-Konto in /data selbst nicht schreiben darf (das
Wurzelverzeichnis /data gehört root, nur die Unterordner wie /data/gitea und /data/git
gehören dem git-Benutzer) und der Dump sich sonst rekursiv in das gepackte Datenverzeichnis
schreiben würde. Die fertige Zip holst du
anschließend aus dem Container heraus – dorthin, wo restic sie mitsichert:
docker compose cp forgejo:/tmp/forgejo-dump.zip ./forgejo-dump.zipDie Zip enthält den Datenbank-Dump (forgejo-db.sql), die app.ini und alle Repository-Daten – ein
vollständiger, für sich stehender Wiederherstellungspunkt.
Updates: Forgejo veröffentlicht regelmäßig neue Versionen (aktuell die 16er-Reihe). Für ein Update
setzt du den neuen Tag in der compose.yaml (statt 16.0.3) und ziehst ihn:
docker compose pull && docker compose up -dWeil die Daten im Volume liegen, bleiben Repos und Konten dabei erhalten. Pinne die Version bewusst auf
einen festen Tag statt latest und wirf vor einem Major-Sprung einen Blick in die
Release-Notes – dort stehen eventuelle Migrations-Hinweise. Mache
außerdem vor jedem Update ein frisches Backup: ein Git-Server ohne funktionierendes Backup ist ein
Klumpenrisiko für deinen gesamten Code.
Absichern: Ein öffentlich erreichbarer Git-Server ist ein lohnendes Ziel. Drei Dinge solltest du gleich erledigen: die offene Registrierung deaktivieren (siehe Schritt 3), für dein Admin-Konto unter Einstellungen → Sicherheit die Zwei-Faktor-Authentifizierung einschalten und für den Alltag ein normales Konto statt des Administrators nutzen. Halte Forgejo zeitnah aktuell – die schnellen Releases enthalten auch Sicherheitsfixes. Und veröffentliche nur die Ports, die du wirklich brauchst: nach außen genügen 443 (Traefik) und dein SSH-Git-Port 2222.
Zuletzt aktualisiert: 29.08.2026
Feedback per E-Mail: feedback@serverkueche.de
Wie geht's weiter?

Forgejo Actions: eigener CI/CD-Runner mit Docker
Einen Forgejo-Actions-Runner mit Docker-in-Docker aufsetzen und registrieren: eigene CI/CD-Pipelines auf dem …
Das könnte dir auch schmecken

Die eigene Website mit Hugo hosten – wie die Serverküche selbst
Statische Website mit Hugo bauen und im Docker-Container hinter Traefik ausliefern – schnell, sicher, ohne Datenbank. …

HitKeep: datenschutzfreundliche Web-Analytics selbst hosten
HitKeep mit Docker und Traefik aufsetzen: cookielose, DSGVO-freundliche Website-Statistik auf dem eigenen Server – mit …

Jellyfin selbst hosten: dein eigener Medienserver hinter Traefik
Jellyfin mit Docker hinter Traefik aufsetzen: deine Filme, Serien und Musik streamen – mit HTTPS und der Mediathek auf …