Forgejo nativ auf Ubuntu installieren: Binary, systemd, Nginx und MariaDB
Forgejo als einzelnes Go-Binary nativ auf Ubuntu einrichten: dedizierter Systemuser, MariaDB mit utf8mb4_bin, systemd-Dienst, Nginx als Reverse Proxy mit Let's Encrypt und Härtung nach dem Web-Setup, für Forgejo 15 LTS.
Geprüft am 29.09.2026 · für forgejo 15.0.9
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Forgejo ist der community-getriebene Fork von Gitea, seit 2022 unter dem Dach von Codeberg.org entwickelt. Anders als GitLab CE kommt es als einzelnes statisches Go-Binary ohne Runtime-Abhängigkeiten, Container-Stack oder Kubernetes. Diese Anleitung zeigt Forgejo 15.0.9 (LTS) direkt auf Ubuntu mit systemd-Unit, Nginx-Reverse-Proxy, MariaDB als Produktionsdatenbank und optionalem Let's-Encrypt-SSL, für Administratoren, die jede Schicht selbst kontrollieren und auf Docker verzichten möchten.
Voraussetzungen
- Ubuntu-Server 22.04, 24.04 oder 26.04 LTS (amd64 oder arm64)
- Root- oder sudo-Zugriff auf den Server
- Domain oder Subdomain (z. B.
git.example.com) mit DNS-A-Record auf die Server-IP - Offene Ports: 22 (SSH), 80 (HTTP), 443 (HTTPS) – Port 22 muss vor dem Aktivieren der Firewall freigeschaltet sein
- Mindestens 1 GB RAM (empfohlen: 2 GB+), 10 GB freier Speicher für Repositories
- Forgejo-Binary 15.0.9 von
codeberg.org/forgejo/forgejo/releases
| Komponente | Version / Paket | Zweck |
|---|---|---|
| Forgejo Binary | 15.0.9 LTS (Go, statisch) | Anwendungsserver auf Port 3000 |
| MariaDB | aus den Ubuntu-Paketquellen (24.04: 10.11 LTS) | Produktionsdatenbank mit utf8mb4_bin |
| Nginx | apt (stable) | Reverse Proxy, TLS-Terminierung |
| Certbot | python3-certbot-nginx | Let's Encrypt SSL automatisch |
| systemd | Ubuntu built-in | Service-Management, Autostart |
| git + git-lfs | apt | Pflichtabhängigkeit von Forgejo |
Schritt 1: System vorbereiten und Abhängigkeiten installieren
Aktualisieren Sie das System und installieren Sie die nötigen Pakete. git und git-lfs müssen vor dem ersten Forgejo-Start vorhanden sein, sonst schlägt der Dienst stumm fehl.
sudo apt update && sudo apt upgrade -y
sudo apt install -y git git-lfs wget curl ufw ca-certificates nginx mariadb-serverVerifizieren: git --version und git-lfs --version müssen jeweils eine Versionsnummer ausgeben.
Schritt 2: Forgejo-Binary herunterladen und installieren
Laden Sie die aktuelle LTS-Version herunter und prüfen Sie die SHA256-Prüfsumme, bevor Sie das Binary einsetzen. Die neuere Reihe 16 ist nur bis Ende Oktober 2026 unterstützt; für den Dauerbetrieb ist die LTS-Reihe 15 die ruhigere Wahl.
cd /tmp
wget https://codeberg.org/forgejo/forgejo/releases/download/v15.0.9/forgejo-15.0.9-linux-amd64
# SHA256-Prüfsumme verifizieren (Dateiname muss zur .sha256-Datei passen)
wget https://codeberg.org/forgejo/forgejo/releases/download/v15.0.9/forgejo-15.0.9-linux-amd64.sha256
sha256sum -c forgejo-15.0.9-linux-amd64.sha256
sudo cp forgejo-15.0.9-linux-amd64 /usr/local/bin/forgejo
sudo chmod 755 /usr/local/bin/forgejoFür ARM64-Server (z. B. Hetzner CAX, Raspberry Pi 4/5) ersetzen Sie linux-amd64 durch linux-arm64 bzw. linux-arm-6.
Verifizieren: sha256sum -c meldet OK, forgejo --version gibt Forgejo version 15.0.9 aus.
Schritt 3: Systemuser und Verzeichnisstruktur anlegen
Forgejo läuft unter dem Systemuser git, damit SSH-Clone-URLs die vertraute Form git@git.example.com:Org/Repo.git haben. Der User hat kein Passwort und keine interaktive Shell nach außen.
sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' \
--group --disabled-password --home /home/git git
# Verzeichnisstruktur
sudo mkdir -p /var/lib/forgejo/{data,custom,log}
sudo mkdir -p /etc/forgejo
# Berechtigungen setzen
sudo chown git:git /var/lib/forgejo && sudo chmod 750 /var/lib/forgejo
sudo chown git:git /var/lib/forgejo/log
# /etc/forgejo: während des Web-Setups braucht git Schreibrecht (770)
sudo chown root:git /etc/forgejo && sudo chmod 770 /etc/forgejo| Pfad | Eigentümer | Rechte (Setup) | Rechte (nach Setup) |
|---|---|---|---|
| /usr/local/bin/forgejo | root:root | 755 | 755 |
| /var/lib/forgejo | git:git | 750 | 750 |
| /etc/forgejo | root:git | 770 | 750 |
| /etc/forgejo/app.ini | root:git | (vom Wizard angelegt) | 640 |
| /etc/systemd/system/forgejo.service | root:root | 644 | 644 |
Verifizieren: id git zeigt den Systemuser, ls -ld /var/lib/forgejo /etc/forgejo zeigt Eigentümer und Rechte wie in der Tabelle.
Schritt 4: MariaDB vorbereiten
MariaDB ist die empfohlene Produktionsdatenbank. Entscheidend ist die Collation utf8mb4_bin: Forgejo erwartet case-sensitive Vergleiche und bricht die Ersteinrichtung bei utf8mb4_unicode_ci ab. Findet Forgejo beim Start eine bessere case-sensitive Collation (uca1400_as_cs), stellt es die Datenbank selbst um.
sudo mysql_secure_installation
sudo mysql -u root -p
CREATE USER 'forgejo'@'localhost' IDENTIFIED BY 'StarkesPasswort!';
CREATE DATABASE forgejo CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';
GRANT ALTER, CREATE, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE
ON forgejo.* TO 'forgejo'@'localhost';
FLUSH PRIVILEGES;
EXIT;Verifizieren: sudo mysql -u forgejo -p forgejo -e "SHOW CREATE DATABASE forgejo\G" – in der Ausgabe muss utf8mb4_bin stehen.
| Datenbank | Empfehlung | Besonderheit |
|---|---|---|
| SQLite3 | Test und kleine Instanzen | Kein Extra-Setup, bei vielen gleichzeitigen Zugriffen begrenzt |
| MariaDB/MySQL | Produktion (Standard) | utf8mb4_bin Pflicht, unbegrenzte Nutzer |
| PostgreSQL | Produktion (Alternative) | Vollständig unterstützt, ebenfalls empfohlen |
Schritt 5: systemd-Service einrichten
Der offizielle systemd-Service liegt als Vorlage auf Codeberg. Für MariaDB müssen die Wants=- und After=-Zeilen im [Unit]-Block aktiv sein, sonst startet Forgejo beim Booten vor der Datenbank und schlägt sporadisch fehl.
sudo wget -O /etc/systemd/system/forgejo.service \
https://codeberg.org/forgejo/forgejo/raw/branch/forgejo/contrib/systemd/forgejo.serviceEntfernen Sie in der Service-Datei im [Unit]-Block die Kommentarzeichen der MariaDB-Abhängigkeit:
[Unit]
Description=Forgejo Git Service
After=network.target mariadb.service
Wants=mariadb.serviceSchlägt der Download fehl, legen Sie die Datei mit dem Inhalt der offiziellen Vorlage an:
[Unit]
Description=Forgejo Git Service
After=network.target mariadb.service
Wants=mariadb.service
[Service]
Type=notify
User=git
Group=git
WorkingDirectory=/var/lib/forgejo/
ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini
Restart=always
RestartSec=2s
Environment=USER=git HOME=/home/git FORGEJO_WORK_DIR=/var/lib/forgejo
[Install]
WantedBy=multi-user.targetDanach laden Sie systemd neu und starten den Dienst:
sudo systemctl daemon-reload
sudo systemctl enable forgejo.service
sudo systemctl start forgejo.service
sudo systemctl status forgejo.serviceVerifizieren: sudo systemctl status forgejo.service zeigt active (running). Mit sudo journalctl -n 50 --unit forgejo.service prüfen Sie die letzten Log-Zeilen – nach dem ersten Start ohne app.ini erscheint eine Meldung über den Web-Setup-Wizard.
Schritt 6: Nginx als Reverse Proxy konfigurieren
Forgejo lauscht intern auf 127.0.0.1:3000, Nginx übernimmt Port 80/443. merge_slashes off verhindert, dass URL-kodierte Schrägstriche in Repository-Pfaden zusammengefasst werden (sonst API-404-Fehler). Die WebSocket-Header Upgrade und Connection braucht das Web-Interface für Live-Aktualisierungen.
sudo nano /etc/nginx/sites-available/forgejo
server {
listen 80;
listen [::]:80;
server_name git.example.com;
merge_slashes off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 512M;
}
}
sudo ln -s /etc/nginx/sites-available/forgejo /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxclient_max_body_size 512M ist notwendig: Nginx verwirft große Git-Pushes und LFS-Uploads sonst mit HTTP 413. Für sehr große Repositories erhöhen Sie den Wert.
Verifizieren: sudo nginx -t gibt syntax is ok und test is successful aus.
Schritt 7: SSL mit Let's Encrypt (Certbot)
Certbot konfiguriert Nginx für HTTPS und richtet die Zertifikatserneuerung per Cronjob ein. Stellen Sie sicher, dass der DNS-A-Record für git.example.com auf die Server-IP zeigt; Certbot validiert per HTTP-Challenge.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d git.example.comAlternativ beherrscht Forgejo TLS selbst (integrierter ACME-Client); da Nginx ohnehin als Reverse Proxy läuft, ist Certbot meist flexibler. Eine Anleitung mit Caddy ist unten verlinkt.
Verifizieren: sudo certbot certificates zeigt das Zertifikat mit Ablaufdatum. curl -sI https://git.example.com liefert einen HTTP-Status ohne Zertifikatsfehler.
Schritt 8: Firewall konfigurieren
Wichtig: Port 22 (SSH) muss vor dem Aktivieren von UFW freigeschaltet sein – sonst sperren Sie sich vom Server aus.
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enableSSH auf Port 22 läuft direkt am git-User, nicht über Nginx. Forgejo verwaltet ~/.ssh/authorized_keys des git-Users automatisch, wenn Nutzer ihren Schlüssel im Web-Interface hinterlegen.
Verifizieren: sudo ufw status zeigt Status: active mit Freigaben für OpenSSH sowie 80 und 443/tcp, eine zweite SSH-Sitzung lässt sich weiterhin öffnen.
Schritt 9: Web-Setup abschließen
Rufen Sie http://git.example.com (nach Certbot https://) auf. Die Ersteinrichtungsseite erscheint nur beim allerersten Aufruf und speichert die Konfiguration in /etc/forgejo/app.ini.
Fülle das Formular wie folgt aus:
- Datenbanktyp: MySQL/MariaDB
- Host:
127.0.0.1:3306 - Datenbankname:
forgejo, User:forgejo, Passwort: wie in Schritt 4 gesetzt - Domain:
git.example.com - Base URL:
https://git.example.com/(mit abschließendem Slash!) - Admin-Konto anlegen
Nach dem Abschicken startet Forgejo ggf. kurz neu und leitet auf das Dashboard weiter.
Verifizieren: /etc/forgejo/app.ini existiert, und die Anmeldung mit dem neuen Admin-Konto unter https://git.example.com gelingt.
Schritt 10: Post-Install-Härtung und Produktions-app.ini
Nach dem Web-Setup sind zwei Maßnahmen zwingend: /etc/forgejo und app.ini auf sichere Berechtigungen setzen (der Wizard brauchte temporär Schreibrecht), und INSTALL_LOCK = true setzen, sonst kann jeder mit Zugriff auf die URL die Instanz neu konfigurieren oder übernehmen.
sudo systemctl stop forgejo.service
sudo chmod 750 /etc/forgejo
sudo chmod 640 /etc/forgejo/app.ini
sudo systemctl start forgejo.serviceEmpfohlene Produktions-Einstellungen für /etc/forgejo/app.ini (Auszug; ergänzen oder passen Sie an, was der Web-Wizard bereits gesetzt hat):
[security]
INSTALL_LOCK = true
SECRET_KEY = <generiert via: sudo -u git forgejo generate secret SECRET_KEY>
INTERNAL_TOKEN = <generiert via: sudo -u git forgejo generate secret INTERNAL_TOKEN>
MIN_PASSWORD_LENGTH = 12
PASSWORD_COMPLEXITY = lower,upper,digit,spec
[server]
DOMAIN = git.example.com
ROOT_URL = https://git.example.com/
HTTP_ADDR = 127.0.0.1
HTTP_PORT = 3000
APP_DATA_PATH = /var/lib/forgejo/data
OFFLINE_MODE = true
[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = forgejo
USER = forgejo
PASSWD = StarkesPasswort!
CHARSET_COLLATION = utf8mb4_bin
[repository]
ROOT = /var/lib/forgejo/repositories
[log]
MODE = file
LEVEL = info
ROOT_PATH = /var/lib/forgejo/log
[service]
DISABLE_REGISTRATION = true
[repository.upload]
FILE_MAX_SIZE = 4095
MAX_FILES = 20Wichtig: SECRET_KEY und INTERNAL_TOKEN niemals manuell erfinden oder leer lassen, sondern mit sudo -u git forgejo generate secret SECRET_KEY erzeugen. Der Wizard setzt sie normalerweise; prüfen Sie, ob sie vorhanden sind.
Für Admin-Befehle auf der Kommandozeile ist ein kleiner CLI-Wrapper praktisch:
sudo tee /usr/local/bin/forgejo-cli << 'EOF'
#!/bin/sh
sudo -u git forgejo -w /var/lib/forgejo -c /etc/forgejo/app.ini "$@"
EOF
sudo chmod 755 /usr/local/bin/forgejo-cli
# Beispiel: forgejo-cli admin user listVerifizieren: forgejo-cli admin user list listet alle vorhandenen Benutzer auf.
Troubleshooting / Typische Fehler
Ersteinrichtung schlägt mit Datenbankfehler fehl
Ursache: falsche Collation (utf8mb4_unicode_ci statt utf8mb4_bin). Lösung: Datenbank droppen und korrekt neu anlegen; ein späterer Wechsel ist aufwändig.
Forgejo startet nach Reboot nicht
Ursache: Wants=mariadb.service und After=mariadb.service fehlen in der systemd-Unit. Lösung: Service-Datei anpassen (Schritt 5), dann sudo systemctl daemon-reload.
HTTP 413 bei großen Git-Pushes
Ursache: client_max_body_size zu klein (Standard: 1 MB). Lösung: auf mindestens 512M erhöhen, Nginx neu starten.
404-Fehler bei bestimmten API-Requests
Ursache: merge_slashes off fehlt; URL-kodierte Schrägstriche werden zusammengefasst. Lösung: Direktive im server {}-Block ergänzen.
Web-Setup-Wizard erzeugt keine app.ini
Ursache: /etc/forgejo hat chmod 750 statt 770, der git-User kann nicht schreiben. Lösung: sudo chmod 770 /etc/forgejo während des Setups, danach auf 750 zurücksetzen.
Binary startet nicht
Ursache: chmod 755 vergessen, das Binary ist nicht ausführbar. Prüfen mit ls -la /usr/local/bin/forgejo.
app.ini ROOT_URL falsch
Ursache: ROOT_URL enthält http:// statt https:// oder der abschließende Slash fehlt; generierte Links (Clone-URLs, E-Mail-Links) sind dann falsch. Lösung: app.ini anpassen, Forgejo neu starten.
Häufige Fragen
Kann ich später von SQLite auf MariaDB migrieren?
Ja, mit Aufwand: forgejo dump --database mysql erzeugt eine Sicherung mit SQL-Dump in MySQL-Syntax, den Sie in eine leere MariaDB-Datenbank einspielen, bevor Sie app.ini umstellen. Für Produktivbetrieb gleich mit MariaDB starten.
Wie update ich Forgejo auf eine neue Version?
Zuerst Datenbank und /var/lib/forgejo sichern. Dann Service stoppen, altes Binary sichern (sudo cp /usr/local/bin/forgejo /usr/local/bin/forgejo.bak), neues Binary mit Prüfsumme wie in Schritt 2 installieren, Service starten; Datenbank-Migrationen laufen automatisch. Vor einem Hauptversionswechsel den Upgrade-Guide lesen.
Läuft Forgejo auch auf ARM-Servern (z. B. Hetzner CAX, Raspberry Pi)?
Ja, siehe Schritt 2: Binaries für linux-arm64 und linux-arm-6 auf Codeberg; nur den Download-Link anpassen.
Wie richte ich SSH-Key-Authentifizierung ein?
SSH läuft direkt über den git-User auf Port 22, außerhalb von Nginx. Nutzer laden ihren öffentlichen Schlüssel unter „Einstellungen → SSH-/GPG-Schlüssel“ hoch; Forgejo verwaltet /home/git/.ssh/authorized_keys automatisch.
Wie konfiguriere ich E-Mail-Versand?
Im app.ini unter [mailer]: ENABLED = true, PROTOCOL = smtp, SMTP_ADDR = mail.example.com, SMTP_PORT = 587, USER = ..., PASSWD = ..., FROM = forgejo@example.com. Anschließend Forgejo neu starten.
Wie sperre ich die öffentliche Registrierung?
In app.ini unter [service]: DISABLE_REGISTRATION = true. Konten legt dann nur der Admin im Web-Interface oder via forgejo-cli admin user create an.
Fazit
Das native Binary spart gegenüber Docker eine Schicht: direkteres Debugging, systemd verwaltet den Dienst wie andere Serverdienste. Kritisch sind die MariaDB-Collation, die temporären Schreibrechte auf /etc/forgejo während des Web-Setups und INSTALL_LOCK = true. Rechnen Sie mit etwa 60 Minuten.
Weiterführende Anleitungen und Quellen
- Nginx als Reverse Proxy mit TLS manuell einrichten – Grundlagen für erweiterte Nginx-Konfigurationen
- Caddy als Reverse-Proxy mit automatischem HTTPS – wann er Nginx und Traefik schlägt – Alternative zu Certbot/Nginx
- systemd-Service selbst erstellen und verwalten – Hintergrundwissen zu Unit-Dateien und Abhängigkeiten
- MariaDB / MySQL installieren und absichern – Vertiefte MariaDB-Konfiguration und Härtung
- Nextcloud nativ auf Ubuntu installieren (LEMP ohne Docker) – gleicher Stack-Ansatz für eine andere Plattform
- Gitea mit Docker: eigener Git-Server als GitHub-Alternative – Docker-Variante zum Vergleich
Offizielle Quellen:


