GitLab CE mit Docker installieren: Vollständige DevOps-Plattform mit Git, CI/CD und Container-Registry
GitLab CE mit Docker Compose selbst hosten: Git-Hosting, CI/CD mit GitLab Runner und Container-Registry einrichten, Runner mit Authentifizierungstoken registrieren, Backups und Updates planen.
Geprüft am 30.09.2026 · für gitlab-ce 19.4.1-ce.0
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

GitLab Community Edition (CE) bündelt Git-Hosting, Merge Requests, CI/CD-Pipelines, Container-Registry und Package-Registry in einer selbst gehosteten Instanz. Die MIT-lizenzierte Plattform läuft als ein Docker-Container auf Ihrem Linux-Server. Diese Anleitung führt von der leeren VM bis zur laufenden Instanz mit registriertem GitLab Runner für CI/CD-Pipelines.
Voraussetzungen
- Linux-Host oder VM – z. B. Ubuntu 24.04, Debian 12/13 oder Rocky Linux 9. Docker Desktop für Windows unterstützt GitLab nicht.
- Docker Engine ≥ 20.10.10 und Docker Compose Plugin v2 (
docker composeohne Bindestrich) installiert. Falls noch nicht vorhanden: Docker und Docker Compose auf Linux installieren (Ubuntu/Debian). - RAM: mindestens 8 GB (Untergrenze laut GitLab für speicherarme Umgebungen), 16 GB als Richtwert für eine Einzelinstanz. PostgreSQL, Redis, Sidekiq und Puma laufen alle im selben Container.
- CPU: 8 vCPU sind der GitLab-Richtwert für eine Einzelinstanz, x86_64 oder ARM64.
- Speicher: mindestens 40 GB auf SSD plus Platz für Repositories und CI/CD-Artefakte.
- Statischer Hostname oder FQDN für den Wert
external_url; ohne feste Adresse entstehen fehlerhafte Clone-URLs. - Optional: Reverse Proxy (z. B. Caddy oder Nginx) für HTTPS-Terminierung; SMTP-Relay für E-Mail-Benachrichtigungen (GitLab hat keinen eingebauten Mailserver).
Schritt 1: Projektordner und Verzeichnisstruktur anlegen
Konfiguration, Logs und Repositories liegen unter dem Basispfad GITLAB_HOME. GitLab empfiehlt /srv/gitlab.
sudo mkdir -p /srv/gitlab
sudo mkdir -p /opt/gitlab-compose
cd /opt/gitlab-compose/opt/gitlab-compose nimmt compose.yaml und .env auf.
Verifizieren:
ls -la /srv/gitlab /opt/gitlab-composeErwartetes Ergebnis: beide Verzeichnisse existieren, Eigentümer root. Die Unterordner config, logs und data legt Docker beim ersten Start an.
Schritt 2: .env-Datei mit Zugangsdaten anlegen
Die .env enthält die variablen Werte und gehört nicht in ein Git-Repository. Erstellen Sie die Datei unter /opt/gitlab-compose/.env und passen Sie die drei Pflichtfelder an:
# /opt/gitlab-compose/.env
# Basispfad fuer alle Volume-Mounts auf dem Host
GITLAB_HOME=/srv/gitlab
# Hostname oder IP-Adresse der GitLab-Instanz
# Muss mit dem Port in GITLAB_OMNIBUS_CONFIG uebereinstimmen
GITLAB_HOSTNAME=gitlab.example.com
# Initiales Root-Passwort (mind. 12 Zeichen, Sonderzeichen erlaubt)
# Wird bei erstem Start gesetzt; Datei /etc/gitlab/initial_root_password
# wird nach 24 h automatisch geloescht!
GITLAB_ROOT_PASSWORD=ChangeMe_MinLength12!Schützen Sie die Datei vor unbefugtem Zugriff:
chmod 600 /opt/gitlab-compose/.envVerifizieren:
ls -la /opt/gitlab-compose/.envErwartetes Ergebnis: Berechtigungen -rw-------, Eigentümer root.
Schritt 3: compose.yaml erstellen
Die compose.yaml definiert den GitLab-Container und einen GitLab Runner für CI/CD-Pipelines.
# /opt/gitlab-compose/compose.yaml
services:
gitlab:
image: gitlab/gitlab-ce:19.4.1-ce.0
container_name: gitlab
restart: always
hostname: ${GITLAB_HOSTNAME}
# shm_size PFLICHT: ohne diese Zeile schreibt Prometheus in einen
# zu kleinen /dev/shm-Bereich und erzeugt "unmapped file"-Fehler
shm_size: '256m'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://${GITLAB_HOSTNAME}:8929'
# SSH-Port: muss mit dem Host-seitigen Port-Mapping uebereinstimmen
gitlab_rails['gitlab_shell_ssh_port'] = 2424
# Root-Passwort aus .env setzen (Alternative: nach Start manuell auslesen)
gitlab_rails['initial_root_password'] = '${GITLAB_ROOT_PASSWORD}'
# Optional: Container-Registry aktivieren
# registry_external_url 'http://${GITLAB_HOSTNAME}:5050'
# Optional: SMTP (kein Mailserver eingebaut)
# gitlab_rails['smtp_enable'] = true
# gitlab_rails['smtp_address'] = "smtp.example.com"
# gitlab_rails['smtp_port'] = 587
ports:
- '8929:8929'
- '2424:22'
volumes:
- '${GITLAB_HOME}/config:/etc/gitlab'
- '${GITLAB_HOME}/logs:/var/log/gitlab'
- '${GITLAB_HOME}/data:/var/opt/gitlab'
logging:
driver: 'json-file'
options:
max-size: '50m'
max-file: '5'
gitlab-runner:
image: gitlab/gitlab-runner:v19.4.1
container_name: gitlab-runner
restart: always
depends_on:
- gitlab
volumes:
- '${GITLAB_HOME}/runner/config:/etc/gitlab-runner'
- '/var/run/docker.sock:/var/run/docker.sock'
logging:
driver: 'json-file'
options:
max-size: '20m'
max-file: '3'Port in external_url (:8929) und Port-Mapping (8929:8929) müssen übereinstimmen, sonst zeigt GitLab falsche Clone-URLs. Werte aus GITLAB_OMNIBUS_CONFIG landen nicht in /etc/gitlab/gitlab.rb, sondern werden bei jedem Container-Start neu ausgewertet.
Port 8929 überträgt unverschlüsselt HTTP und ist auf allen Schnittstellen erreichbar. Geben Sie ihn per Firewall nur im internen Netz frei; für Zugriff aus dem Internet gehört ein Reverse Proxy mit HTTPS davor. Der Runner erhält über /var/run/docker.sock Vollzugriff auf Docker und damit faktisch Root-Rechte auf dem Host. Lassen Sie deshalb nur vertrauenswürdige Projekte Jobs auf diesem Runner ausführen.
Verifizieren:
docker compose -f /opt/gitlab-compose/compose.yaml configErwartetes Ergebnis: Docker Compose gibt die vollständig interpolierte Konfiguration ohne Fehler aus; alle ${...}-Variablen sind durch Werte aus der .env ersetzt.
Schritt 4: GitLab starten und Initialisierung abwarten
Starten Sie den Stack aus dem Compose-Verzeichnis heraus:
cd /opt/gitlab-compose
docker compose up -dDocker lädt das Image (ca. 1,2 GB komprimiert) und startet den Container. Die erste Initialisierung dauert 3 bis 5 Minuten, auf langsamerer Hardware bis zu 10 Minuten. In dieser Zeit zeigt der Browser „502 Whoops, GitLab is taking too much time to respond“. Das ist der normale Initialisierungsablauf.
# Logs live verfolgen (mit Ctrl+C abbrechen)
docker compose logs -f gitlab
# Auf das Signal warten, dass GitLab bereit ist:
docker compose logs -f gitlab | grep -i 'server booted'Eckdaten im Überblick:
| Parameter | Wert |
|---|---|
| Image | gitlab/gitlab-ce:19.4.1-ce.0 |
| Web-UI (HTTP) | Port 8929 → http://HOSTNAME:8929 |
| HTTPS | über Reverse Proxy (siehe Häufige Fragen) |
| Git SSH | Host-Port 2424 → Container-Port 22 |
| Config-Volume | ${GITLAB_HOME}/config:/etc/gitlab |
| Logs-Volume | ${GITLAB_HOME}/logs:/var/log/gitlab |
| Daten-Volume | ${GITLAB_HOME}/data:/var/opt/gitlab |
| shm_size | 256m (Pflicht) |
| Min. RAM | 8 GB (Richtwert 16 GB) |
| CPU | 8 vCPU (Richtwert) |
| ARM64 | ab v18.1/v18.2 offiziell multi-arch |
Verifizieren:
docker compose ps
NAME IMAGE STATUS PORTS
gitlab gitlab/gitlab-ce:19.4.1-ce.0 Up 5 minutes (healthy) 0.0.0.0:2424->22/tcp, 0.0.0.0:8929->8929/tcp
gitlab-runner gitlab/gitlab-runner:v19.4.1 Up 5 minutesSobald GitLab vollständig gestartet ist:
curl -I http://localhost:8929Erwartetes Ergebnis: HTTP/1.1 302 Found mit Location: http://HOSTNAME:8929/users/sign_in.
Schritt 5: Erst-Einrichtung im Browser und Root-Passwort sichern
Rufen Sie http://HOSTNAME:8929 im Browser auf. GitLab leitet auf die Login-Seite weiter. Melden Sie sich mit dem Benutzernamen root und dem in der .env gesetzten Passwort an.
Haben Sie das Root-Passwort nicht über GITLAB_OMNIBUS_CONFIG gesetzt, lesen Sie das generierte Passwort aus:
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_passwordWichtig: GitLab löscht diese Datei nach 24 Stunden automatisch. Sichern Sie das Passwort sofort. Nehmen Sie nach dem ersten Login diese Grundkonfiguration im Bereich Admin vor:
- Sign-up deaktivieren (Admin → Settings → General → Sign-up restrictions, Häkchen bei Sign-up enabled entfernen).
- E-Mail-Benachrichtigungen: SMTP-Einstellungen in
GITLAB_OMNIBUS_CONFIGergänzen. - Root-Passwort ändern: Avatar oben → Edit profile → Password.
Verifizieren: Login mit root funktioniert, Dashboard lädt ohne Fehler, der Admin-Bereich ist erreichbar unter http://HOSTNAME:8929/admin.
Schritt 6: GitLab Runner registrieren für CI/CD-Pipelines
Der GitLab-Runner-Container läuft seit Schritt 4, ist aber noch nicht mit der GitLab-Instanz verbunden. CI/CD-Jobs bleiben in der Warteschlange, bis ein Runner registriert ist. Seit GitLab 16 erzeugen Sie den Runner zuerst in der Oberfläche und erhalten ein Runner-Authentifizierungstoken; das frühere Registrierungstoken („Register an instance runner“) gilt als veraltet:
- Admin → CI/CD → Runners → Create instance runner, Betriebssystem Linux wählen, Tags setzen oder Run untagged aktivieren, Create runner.
- Das angezeigte Token mit Präfix
glrt-kopieren. GitLab zeigt es nur während der Registrierung an.
Registrieren Sie den Runner dann im Container:
docker exec -it gitlab-runner gitlab-runner registerDie interaktiven Abfragen:
Enter the GitLab instance URL:
# Eingabe: http://gitlab.example.com:8929
Enter the registration token:
# Eingabe: glrt-... (Token aus der Oberfläche)
Enter a name for the runner:
# Eingabe: docker-runner
Enter an executor:
# Eingabe: docker
Enter the default Docker image:
# Eingabe: alpine:3.22Der Runner speichert seine Konfiguration unter ${GITLAB_HOME}/runner/config/config.toml.
Verifizieren:
docker compose logs gitlab-runner | tail -20Erwartetes Ergebnis: keine ERROR-Zeilen; unter Admin → CI/CD → Runners erscheint der Runner als online. Legen Sie eine einfache .gitlab-ci.yml ins Repository, um einen Test-Job auszulösen:
test-job:
script:
- echo "Pipeline funktioniert!"Schritt 7: Container-Registry aktivieren (optional)
Die Container-Registry ist standardmäßig deaktiviert. Ergänzen Sie registry_external_url und ein Port-Mapping:
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://${GITLAB_HOSTNAME}:8929'
gitlab_rails['gitlab_shell_ssh_port'] = 2424
gitlab_rails['initial_root_password'] = '${GITLAB_ROOT_PASSWORD}'
registry_external_url 'http://${GITLAB_HOSTNAME}:5050'
ports:
- '8929:8929'
- '2424:22'
- '5050:5050'Anschließend den Stack neu starten:
cd /opt/gitlab-compose
docker compose up -dVerifizieren:
curl -I http://localhost:5050/v2/Erwartetes Ergebnis: HTTP/1.1 401 Unauthorized. Das zeigt, dass die Registry läuft und eine Authentifizierung erwartet. Anmeldung mit docker login HOSTNAME:5050 und GitLab-Zugangsdaten. Docker akzeptiert eine Registry ohne HTTPS nur, wenn sie auf dem Client als insecure-registries eingetragen ist; für den Produktivbetrieb gehört HTTPS davor.
Schritt 8: Updates und Backups
Updates durchführen
GitLab erlaubt keine Sprünge über Major-Versionen (z. B. nicht 17.x direkt auf 19.x). Prüfen Sie den Upgrade-Pfad unter docs.gitlab.com/update/upgrade_paths/. Minor-Updates (z. B. 19.3.x auf 19.4.x) laufen so:
# 1. Backup erstellen (siehe unten)
# 2. Image-Tag in compose.yaml auf neue Version aendern, dann:
cd /opt/gitlab-compose
docker compose pull
docker compose up -dDatenbankmigrationen laufen beim Start automatisch, GitLab ist dabei einige Minuten nicht erreichbar.
Backups erstellen
Ein vollständiges Backup besteht aus zwei Teilen:
# Teil 1: Repositories, Issues, CI/CD-Konfigurationen
docker exec -t gitlab gitlab-backup create
# Teil 2: Secrets-Datei (wird von gitlab-backup create NICHT gesichert!)
# Ohne diese Datei sind alle CI/CD-Variablen und 2FA-Secrets verloren
cp /srv/gitlab/config/gitlab-secrets.json /pfad/zum/backup-ziel/gitlab-secrets.jsonDie Backup-Datei liegt unter /srv/gitlab/data/backups/. Eine Backup-Strategie mit Kopie außer Haus zeigt die Anleitung 3-2-1-Backup-Strategie umsetzen: Restic, USB-Disk und S3-Cloud.
Verifizieren:
ls -lh /srv/gitlab/data/backups/Erwartetes Ergebnis: Datei mit Namensschema TIMESTAMP_gitlab_backup.tar vorhanden.
Troubleshooting / Typische Fehler
- „writing value to /dev/shm/gitlab/sidekiq/gauge... failed with unmapped file“ –
shm_size: '256m'fehlt. Ergänzen unddocker compose up -dausführen. - Falsche Clone-URLs – Port in
external_urlpasst nicht zum Port-Mapping (siehe Schritt 3). - „502 Whoops“ nach dem ersten Start – GitLab initialisiert sich noch. 3 bis 5 Minuten warten und Logs beobachten:
docker compose logs -f gitlab | grep -i booted. - Root-Passwort verloren – Reset über die Rails-Konsole:
docker exec -it gitlab gitlab-rails console→user = User.find_by(username: 'root'); user.password = 'NeuesPasswort12!'; user.save! - CI/CD-Jobs warten endlos – Runner nicht registriert, falsche URL oder Job-Tags passen nicht zum Runner. Schritt 6 wiederholen,
docker compose logs gitlab-runnerprüfen. - Container startet nicht, „ThreadError: Operation not permitted“ – Docker älter als 20.10.10. Docker aktualisieren:
apt-get upgrade docker-ce docker-ce-cli containerd.io. - OOM-Killer beendet Prozesse – Zu wenig RAM (mindestens 8 GB). Mit
docker stats gitlabprüfen. - Host-Festplatte läuft voll – Log-Rotation fehlt. Die
logging-Sektion der obigencompose.yamlübernehmen. - Upgrade schlägt fehl – Pflicht-Zwischenversion übersprungen. Backup einspielen und Upgrade-Pfad unter docs.gitlab.com/update/upgrade_paths/ einhalten.
Häufige Fragen
Wie lange dauert der erste Start von GitLab CE?
3 bis 5 Minuten, auf langsamer Hardware bis zu 10 Minuten (Details in Schritt 4).
Wie unterscheidet sich GitLab CE von GitLab EE?
Die Community Edition (CE) ist MIT-lizenziert und enthält Git-Hosting, Merge Requests, CI/CD, SAST, Container-Registry, Issue-Tracking, Wiki und Package-Registry. Der Enterprise Edition vorbehalten sind unter anderem DAST, das Security-Dashboard, GitLab Geo und erweiterte Compliance-Funktionen. Für die meisten KMU-Teams reicht CE.
Funktioniert GitLab CE auf ARM64-Servern?
Ja. Seit GitLab 18 gibt es offizielle Multi-Arch-Images (amd64 und arm64) unter gitlab/gitlab-ce, Docker wählt die passende Architektur automatisch. Die RAM-Anforderung von mindestens 8 GB gilt auch hier.
Wie richte ich HTTPS ein?
Entweder über Let's Encrypt im Container (in GITLAB_OMNIBUS_CONFIG: external_url 'https://…' und letsencrypt['enable'] = true, erfordert öffentlich erreichbare Ports 80 und 443 mit entsprechendem Port-Mapping) oder über einen Reverse Proxy wie Caddy oder Nginx, der Anfragen an den internen Port 8929 weiterleitet. Bei mehreren Diensten auf einem Server ist der Reverse Proxy die bessere Wahl.
Wie führe ich ein Backup durch?
Mit docker exec -t gitlab gitlab-backup create plus einer Kopie von ${GITLAB_HOME}/config/gitlab-secrets.json, die das Backup nicht enthält (siehe Schritt 8).
Wie aktualisiere ich GitLab auf eine neue Version?
Backup erstellen, Image-Tag in compose.yaml auf die Zielversion setzen, docker compose pull && docker compose up -d ausführen (siehe Schritt 8). Prüfen Sie vorher den offiziellen Upgrade-Pfad unter docs.gitlab.com/update/upgrade_paths/ prüfen.
Warum braucht GitLab keinen separaten Datenbank-Container?
Das Omnibus-Paket bündelt PostgreSQL, Redis, Sidekiq, Puma, Nginx und Prometheus in einem Container. Das vereinfacht den Betrieb und erklärt den hohen RAM-Bedarf.
Fazit
GitLab CE vereint Git-Hosting, CI/CD-Pipelines und Container-Registry in einem Docker-Container und ersetzt damit mehrere separate Dienste. Dafür brauchen Sie mindestens 8 GB RAM, Upgrades entlang des offiziellen Upgrade-Pfads und eine Sicherung von gitlab-secrets.json vor jedem Upgrade.
Als schlankere Alternative ohne eingebaute CI/CD eignet sich Gitea mit Docker: eigener Git-Server als GitHub-Alternative.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
- Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS
- Gitea mit Docker: eigener Git-Server als GitHub-Alternative
- 3-2-1-Backup-Strategie umsetzen: Restic, USB-Disk und S3-Cloud
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only
Offizielle Quellen: GitLab Docs: Install GitLab in a Docker container · GitLab Docs: Configure GitLab running in a Docker container · Docker Hub: gitlab/gitlab-ce


