Gitea für deinen eigenen Git-Server selbst hosten
Folge dem auf deinem eigenen Server. Kostenlos starten, keine Karte nötig
Du willst deine Repositories auf einer Maschine, die du kontrollierst: privater Code, der deine Infrastruktur nie verlässt, keine Preise pro Sitzplatz, und eine Web-Oberfläche, die dein Team schon kennt. Gitea gibt dir das in einem Container: Repository-Browsing, Pull Requests, Issues, eine Package-Registry und Git über HTTPS und SSH. Diese Anleitung bringt dich von einem leeren Server zu Gitea auf deiner eigenen Domain, mit HTTPS über Caddy, SSH-Pushes auf einem eigenen Port, und einem Backup, das du mindestens einmal wiederhergestellt hast. Der letzte Teil zeigt die Ein-Klick-Version auf Railyard.
Diese Anleitung nutzt Gitea 28.2.0, die aktuelle Version, aus Giteas eigener Registry unter docker.gitea.com. Gitea ist im September 2026 von 1.x-Versionsnummern zu 28.0.0 gewechselt, ein “28”-Tag ist also die neuere Version, kein Tippfehler.
Was du brauchst
- Einen Server. Gitea ist leichtgewichtig. Ein Hetzner CX23 (2 vCPU, 4 GB RAM, 40 GB NVMe) kostet 5,99 €/Monat exkl. MwSt. und reicht für ein kleines Team völlig aus. Repositories wachsen, also behalte die Festplatte im Blick.
- Eine Domain oder Subdomain, die du auf den Server zeigen lassen kannst. Diese Anleitung nutzt
git.example.com. - SSH-Zugang als Root oder ein Nutzer mit
sudo. - Einen freien Host-Port für Git über SSH. Die eigene SSH des Servers bleibt auf Port 22, Giteas SSH-Server bekommt also Port 222, das Mapping, das Giteas Dokumentation nutzt.
Schritt 1: DNS auf den Server zeigen lassen und ihn aktualisieren
Lege den Server an und füge einen A-Record für git.example.com hinzu, der auf seine öffentliche IPv4-Adresse zeigt. Mach das zuerst: Caddy kann erst ein Zertifikat bekommen, wenn der Name zu deinem Server aufgelöst wird.
ssh root@203.0.113.20
apt update && apt upgrade -y
Prüfe von deiner eigenen Maschine aus den Record:
dig +short git.example.com
Du solltest die IP deines Servers sehen. Falls noch nicht, mach weiter und prüfe vor Schritt 5 erneut.
Schritt 2: Docker installieren
Gitea und Caddy laufen als Container, du brauchst also nur Docker Engine mit dem Compose-Plugin:
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker compose version
Du solltest eine Docker Compose version-Zeile sehen.
Schritt 3: Die Compose-Datei schreiben
Gitea läuft auf SQLite, es sei denn, du zeigst es auf eine andere Datenbank. SQLite hält alles in einem Volume und ist für ein kleines Team in Ordnung, deshalb nutzt diese Anleitung es (die FAQ behandelt Postgres). Lege das Verzeichnis an:
mkdir -p /opt/gitea/backups
cd /opt/gitea
Speichere das als /opt/gitea/compose.yaml, mit deiner eigenen Domain:
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
depends_on:
- gitea
gitea:
image: docker.gitea.com/gitea:28.2.0
restart: unless-stopped
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__server__DOMAIN: git.example.com
GITEA__server__ROOT_URL: https://git.example.com/
GITEA__server__SSH_DOMAIN: git.example.com
GITEA__server__SSH_PORT: "222"
volumes:
- gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "222:22"
volumes:
gitea-data:
caddy-data:
caddy-config:
Was das macht:
- Das Image,
USER_UID/USER_GID, die Zeitzonen-Mounts und das222:22-Mapping kommen direkt aus Giteas Docker-Dokumentation. Im Container lauscht ein SSH-Server auf 22 für Git; der Host exponiert ihn als 222. GITEA__section__KEY-Variablen setzen Werte in Giteasapp.ini.ROOT_URLlässt Gitea HTTPS-Links bauen, undSSH_PORTlässt die angezeigten Clone-URLs 222 sagen. Sie füllen auch den Setup-Assistenten vorab.- Giteas Web-Port, 3000, wird nicht veröffentlicht. Caddy erreicht ihn über das Compose-Netzwerk, der einzige Weg im Web ist also HTTPS.
- Alles, was Gitea speichert (Repositories, die SQLite-Datenbank, Uploads und
app.ini), lebt imgitea-data-Volume. Ein benanntes Volume übernimmt auch die Dateieigentümerschaft für dich.
Schritt 4: Die Caddyfile schreiben
Speichere das als /opt/gitea/Caddyfile:
git.example.com {
encode zstd gzip
reverse_proxy gitea:3000
}
Caddy holt ein Let’s-Encrypt-Zertifikat für die Domain, leitet HTTP auf HTTPS um und proxyt die Weboberfläche und Git über HTTPS zu Gitea. Git über SSH läuft nicht durch Caddy: es geht direkt an Port 222. Prüfe beide Dateien:
docker compose config --quiet && echo "compose ok"
docker compose run --rm --no-deps caddy caddy validate --config /etc/caddy/Caddyfile
Du solltest compose ok sehen, dann Valid configuration.
Schritt 5: Die Ports öffnen und starten
Erlaube 80, 443 und 222 in der Firewall deines Cloud-Anbieters. Starte dann den Stack:
docker compose up -d
docker compose ps
docker compose logs -f caddy
Du solltest caddy und gitea mit Status Up sehen, und Caddy loggt, dass es ein Zertifikat für git.example.com erhalten hat. Drücke Ctrl+C und öffne https://git.example.com. Du solltest Giteas Installationsseite sehen.
Schritt 6: Den Setup-Assistenten abschließen
Gitea hat keinen Standard-Account: Der erste Besuch öffnet eine einmalige Installationsseite. Prüfe die Werte, von denen die meisten schon durch die Umgebungsvariablen gefüllt sind:
- Database Type: SQLite3, mit dem Pfad
/data/gitea/gitea.db. - SSH Server Port
222und Gitea Website URLhttps://git.example.com/. Die Environment Configuration-Box unten listet dieGITEA__-Variablen, die in/data/gitea/conf/app.inigeschrieben werden. - Only administrators can create user accounts (no self-registration): aktivieren, wenn nur dein Team Accounts haben soll.
- Administrator Account Settings, unter Optional Settings: setze einen Benutzernamen, eine E-Mail und ein Passwort. Die Seite sagt es klar: Überspringst du das, wird der erste registrierte Nutzer Administrator.
Klicke Install Gitea. Du solltest auf deinem Dashboard landen, eingeloggt als Administrator.
Teste jetzt beide Wege zu pushen. Füge deinen Public Key unter Settings → SSH / GPG Keys hinzu, lege ein Repository namens test-repo an, und dann von deiner Maschine aus:
git clone ssh://git@git.example.com:222/youradmin/test-repo.git
git clone https://git.example.com/youradmin/test-repo.git test-repo-https
Beide Clones sollten erfolgreich sein. Nutze die ssh://-Form mit dem Port: die kurze git@host:owner/repo-Form nutzt immer Port 22.
Schritt 7: Gitea sichern
gitea dump schreibt Repositories, die Datenbank, app.ini und hochgeladene Dateien in ein Archiv. Es muss als Nutzer git laufen, denn Gitea verweigert, als Root zu laufen. Speichere das als /opt/gitea/backup.sh:
#!/usr/bin/env bash
set -euo pipefail
cd /opt/gitea
docker compose exec -T -u git -w /tmp gitea gitea dump -c /data/gitea/conf/app.ini --file - > "backups/gitea-$(date +%F).zip"
find backups -name 'gitea-*.zip' -mtime +14 -delete
--file - streamt das Archiv auf die Standardausgabe, es landet also direkt auf dem Host. Mach es ausführbar, führe es aus, und plane es für 03:00 Uhr mit crontab -e:
chmod +x /opt/gitea/backup.sh
/opt/gitea/backup.sh
unzip -l /opt/gitea/backups/gitea-$(date +%F).zip | tail -3
0 3 * * * /opt/gitea/backup.sh
Du solltest eine Dateiliste sehen, die mit einer Gesamtanzahl endet. Kopiere die Archive auch vom Server weg, zum Beispiel mit rsync auf eine andere Maschine.
Um in einer frischen Installation wiederherzustellen, starte Gitea auf einem leeren Volume, kopiere das Archiv hinein und setze jeden Teil zurück an seinen Platz:
docker compose up -d gitea
docker compose cp backups/gitea-2026-05-25.zip gitea:/tmp/restore.zip
docker compose exec gitea sh -c 'mkdir -p /tmp/r && cd /tmp/r && unzip -q /tmp/restore.zip && mkdir -p /data/gitea/conf /data/git/repositories && cp app.ini /data/gitea/conf/app.ini && cp -a data/. /data/gitea/ && cp -a repos/. /data/git/repositories/ && chown -R git:git /data/gitea /data/git'
docker compose restart gitea
docker compose exec -u git gitea gitea -c /data/gitea/conf/app.ini admin regenerate hooks
Das folgt den Wiederherstellungsschritten in Giteas Backup-Dokumentation für Docker. Du solltest deine Repositories und deinen Administrator-Login wieder sehen, ohne Installationsseite.
Schritt 8: Upgrade
Gitea führt seine Datenbank-Migrationen beim Start aus. Lies die Release-Notes, mach ein Backup, ändere den Image-Tag in compose.yaml, dann:
/opt/gitea/backup.sh
docker compose pull gitea
docker compose up -d gitea
docker compose logs -f gitea
Du solltest sehen, dass Gitea startet und wieder Anfragen bedient. Scheitert der Start, nennt das Log die fehlerhafte Einstellung oder Migration; setze den alten Tag zurück und stelle das Backup wieder her, falls du zurückrollen musst.
Die Abkürzung: mit Railyard
Schritte 2 bis 5 sind das, was die Railyard-Gitea-Vorlage für dich macht: Gitea auf Railyard deployen. Railyard baut Gitea aus seinem Repository mit seinem eigenen Dockerfile, betreibt es auf einem Server, den du besitzt, und gibt ihm eine HTTPS-Adresse. Du kannst deine eigene Domain über den Domains-Tab der App hinzufügen (Domains und HTTPS). Dann schließt du denselben Setup-Assistenten aus Schritt 6 an der URL der App ab: setze Gitea Website URL auf die HTTPS-Adresse der App und lege den Administrator-Account an.
Zwei Dinge, die vor dem Anlegen von Repositories eingestellt werden sollten:
/dataauf einem Volume halten. Die Vorlage hängt keins an, füge alsodata:/dataunter Volumes in den Einstellungen der App hinzu. Volumes bleiben über Deploys hinweg erhalten, und du kannst eins mitrailyard volume:backup <app> datasichern.- Die Datenbank wählen. Die Vorlage hängt kein Datenbank-Addon an, Gitea nutzt also SQLite in
/data. Willst du statt dessen Postgres, füge es zuerst über den Resources-Tab der App hinzu und gib Host, Name, Nutzer und Passwort im Datenbank-Abschnitt des Assistenten ein, denn Datenbanken zu wechseln, wenn Repositories schon existieren, ist mehr Arbeit. Railyards Postgres-Backups sind in Datenbanken und Backups behandelt.
Railyard veröffentlicht Giteas Web-Port über HTTPS, auf Railyard klonst und pushst du also über HTTPS statt SSH. Railyards Free-Plan deckt einen Server plus einen Datenbankserver und drei Apps ab, ohne Karte. Pro kostet 19 $/Monat und Team 49 $/Monat, pro Team.
Troubleshooting
address already in use auf Port 80, 443 oder 222. Finde heraus, was lauscht, mit ss -tlnp | grep -E ':(80|443|222)\s'. Für 222 kannst du einen anderen Host-Port wählen (zum Beispiel 2222:22), solange GITEA__server__SSH_PORT dazu passt.
Clone-URLs zeigen den falschen Host, Port oder http://. Gitea schreibt diese Einstellungen in /data/gitea/conf/app.ini. Prüfe ROOT_URL, DOMAIN, SSH_DOMAIN und SSH_PORT in der Umgebung, erstelle den Container mit docker compose up -d gitea neu, und bestätige, dass sich die Werte in app.ini geändert haben.
Caddy bekommt kein Zertifikat. Prüfe, dass dig +short git.example.com die IP deines Servers zurückgibt und Port 80 in der Firewall deines Anbieters offen ist, da Let’s Encrypt darüber validiert. Caddy wiederholt es selbst, sobald DNS korrekt ist.
Permission denied (publickey) beim SSH-Clone. Stelle sicher, dass der Key in Gitea hinzugefügt ist (nicht in den eigenen authorized_keys des Servers), dass du dich mit der ssh://-URL-Form zu Port 222 verbindest, und dass der Nutzer git ist, nicht dein Gitea-Benutzername.
gitea dump sagt, Gitea darf nicht als Root laufen. Du hast -u git ausgelassen. docker compose exec läuft als Root, sofern du es nicht anders angibst.
Dem Server geht der Speicher aus. Gitea ist im Ruhezustand klein, aber das Klonen oder Pushen eines sehr großen Repositories kann den Speicherbedarf spitzen. Prüfe dmesg | grep -i "out of memory" und docker stats, und vergrößere die Box, falls das wieder passiert.
FAQ
Reicht SQLite, oder sollte ich Postgres nutzen? SQLite ist für ein kleines Team in Ordnung. Giteas Docker-Doku enthält eine Postgres-Variante: füge einen db-Dienst hinzu und setze GITEA__database__DB_TYPE=postgres, GITEA__database__HOST=db:5432, GITEA__database__NAME, GITEA__database__USER und GITEA__database__PASSWD auf dem Gitea-Dienst. Entscheide vor der ersten Installation, denn der Assistent schreibt die Wahl in app.ini.
Kann ich meine Repositories von GitHub oder GitLab mitbringen? Ja. Giteas New Migration-Seite hat Importer für GitHub, GitLab, Gitea und andere Dienste, plus eine einfache Git-Option für jede URL. Die dienstspezifischen Importer können je nach Quelle mehr als nur Code mitbringen, zum Beispiel Issues und Releases.
Hat Gitea CI wie GitHub Actions? Gitea Actions nutzt Workflow-Dateien, die der GitHub-Actions-Syntax nahekommen, und führt sie auf einem separaten Runner aus, den du selbst installierst. Das Einrichten eines Runners geht über diese Anleitung hinaus.
Warum Port 222? Das hält den eigenen SSH-Login des Servers auf 22. Jeder freie Port funktioniert, solange SSH_PORT zur Host-Seite des Mappings passt.
Ein selbst gehosteter Git-Server läuft meist auf drei Dinge hinaus: die richtigen URLs in app.ini, einen SSH-Port, der nicht mit deinem eigenen kollidiert, und ein Backup, das du tatsächlich wiederhergestellt hast. Bekomm das am ersten Tag richtig, und Gitea kümmert sich größtenteils selbst um den Rest.
Warum Leute sich dafür Railyard entscheiden
- Dein eigenes Cloud-Konto. Deploye auf DigitalOcean, Hetzner, Vultr, AWS, OVHcloud oder jedem Linux-Server per SSH, direkt von deinem Anbieter abgerechnet, ohne Aufschlag.
- Ein fester Preis pro Team. Free ist für immer kostenlos: ein Server plus ein Datenbankserver, drei Apps, keine Karte. Pro kostet 19 $ im Monat für bis zu fünf Server und unbegrenzte Apps. Team kostet 49 $ im Monat mit unbegrenzten Servern. Keine Kosten pro App, pro Deployment, pro Sitz oder pro Gigabyte.
- Templates mit einem Klick. Deploye Open-Source-Apps, wie Datenbanken, Analytics und Dev-Tools, mit einem Klick auf deinem eigenen Server.
- Verwaltete Datenbanken. Postgres, MySQL und Redis mit geplanten, wiederherstellungsgeprüften Backups und Point-in-Time-Recovery.
- Push-to-Deploy. Deploye von GitHub, GitLab oder der CLI, mit automatischem HTTPS und Releases ohne Ausfallzeit.