Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Cloud / Hosting 05.07.2026 · 11 min Lesezeit

GitLab CE mit Docker installieren: Vollständige DevOps-Plattform mit Git, CI/CD und Container-Registry

GitLab CE bündelt Git-Hosting, CI/CD-Pipelines, Container-Registry, Security-Scanning und Issue-Tracking in einer einzigen selbst gehosteten Instanz – kostenlos, MIT-lizenziert und per Docker in 30 Minuten betriebsbereit.

GitLab CE mit Docker installieren: Vollständige DevOps Plattform mit Docker Container, Git Repository, CI CD Pipelines, Container Registry, Code Review, Projektverwaltung und Self Hosting für professionelle Softwareentwicklung.

Wer Git-Hosting, CI/CD-Pipelines, Container-Registry und Security-Scanning nicht über drei verschiedene Cloud-Dienste verteilen möchte, findet in GitLab Community Edition eine vollständige Antwort. Die MIT-lizenzierte Plattform läuft als einziger Docker-Container auf deinem eigenen Linux-Server und liefert sofort einsatzbereite Merge-Request-Workflows, integrierte SAST/DAST-Scans, ein eingebettetes Package-Registry und Prometheus-Monitoring – ohne monatliche Gebühren und ohne externe Abhängigkeiten. Diese Anleitung zeigt den vollständigen Weg von der leeren VM bis zur laufenden DevOps-Instanz inklusive GitLab Runner für CI/CD-Pipelines.

Voraussetzungen

  1. Linux-Host oder VM – Ubuntu 22.04/24.04, Debian 12 oder RHEL/Rocky 9 empfohlen. Docker for Windows wird von GitLab wegen Volume-Permissions nicht offiziell unterstützt.
  2. Docker Engine ≥ 20.10.10 und Docker Compose Plugin v2 (docker compose ohne Bindestrich) installiert. Falls noch nicht vorhanden: Docker und Docker Compose auf Linux installieren (Ubuntu/Debian).
  3. RAM: mindestens 4 GB (8 GB empfohlen, 16 GB für 100+ Benutzer). GitLab CE betreibt PostgreSQL, Redis, Sidekiq und Puma alle in einem Container – auf 2-GB-Maschinen bricht GitLab unter Last ab.
  4. CPU: mindestens 4 vCPU (8 vCPU für normale Produktionslast).
  5. Disk: mindestens 40 GB freier Speicher für die Basisinstallation, zusätzlich Platz für Repositories und CI/CD-Artefakte. SSD wird empfohlen.
  6. Statischer Hostname oder FQDN für den Wert external_url; ohne feste Adresse entstehen fehlerhafte Clone-URLs.
  7. 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

Alle GitLab-Daten – Konfiguration, Logs und Repositories – liegen unter einem gemeinsamen Basispfad, der über die Variable GITLAB_HOME gesteuert wird. Der Pfad /srv/gitlab ist die offizielle Empfehlung für Linux-Server.

sudo mkdir -p /srv/gitlab
sudo mkdir -p /opt/gitlab-compose
cd /opt/gitlab-compose

Der Unterordner /opt/gitlab-compose nimmt später compose.yaml und .env auf; die eigentlichen Daten liegen in /srv/gitlab.

Verifizieren:

ls -la /srv/gitlab /opt/gitlab-compose

Erwartetes Ergebnis: beide Verzeichnisse existieren, Eigentümer ist root. Die Unterordner config, logs und data innerhalb von /srv/gitlab legt Docker beim ersten Start automatisch an.

Schritt 2: .env-Datei mit Zugangsdaten anlegen

Die .env-Datei hält alle variablen Werte aus der compose.yaml heraus und darf niemals ins Git-Repository eingecheckt werden. Erstelle die Datei unter /opt/gitlab-compose/.env und passe 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ütze die Datei vor unbefugtem Zugriff:

chmod 600 /opt/gitlab-compose/.env

Verifizieren:

ls -la /opt/gitlab-compose/.env

Erwartetes Ergebnis: Berechtigungen -rw-------, Eigentümer root.

Schritt 3: compose.yaml erstellen

Die folgende compose.yaml definiert den GitLab-Hauptcontainer sowie einen GitLab Runner für CI/CD-Pipelines. Wichtige Details sind direkt kommentiert – insbesondere shm_size, das ohne korrekte Angabe zu Prometheus-Fehlern führt, sowie die Port-Übereinstimmung zwischen external_url und dem gemappten Container-Port.

# /opt/gitlab-compose/compose.yaml
services:
  gitlab:
    image: gitlab/gitlab-ce:17.11.0-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'
      - '443:443'
      - '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:latest
    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'

Zwei Punkte verdienen besondere Aufmerksamkeit: Erstens müssen Port-Angabe in external_url (:8929) und das Port-Mapping (8929:8929) exakt übereinstimmen – weichen sie ab, zeigt GitLab falsche Clone-URLs. Zweitens werden Werte aus GITLAB_OMNIBUS_CONFIG nicht in /etc/gitlab/gitlab.rb geschrieben; sie werden bei jedem Container-Start neu ausgewertet und sind damit nicht persistent im Volume.

Verifizieren:

docker compose -f /opt/gitlab-compose/compose.yaml config

Erwartetes 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

Starte den Stack aus dem Compose-Verzeichnis heraus:

cd /opt/gitlab-compose
docker compose up -d

Docker lädt das Image (ca. 1,2 GB komprimiert) herunter, legt die Volume-Verzeichnisse an und startet den Omnibus-Container. Die erste Initialisierung dauert 3–5 Minuten, auf langsamerer Hardware bis zu 10 Minuten. Während dieser Zeit zeigt der Browser „502 Whoops, GitLab is taking too much time to respond" – das ist kein Fehler, sondern 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:

ParameterWert
Imagegitlab/gitlab-ce:17.11.0-ce.0
Web-UI (HTTP)Port 8929 → http://HOSTNAME:8929
HTTPS (optional)Port 443:443
Git SSHHost-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_size256m (Pflicht)
Min. RAM4 GB (empf. 8 GB)
Min. CPU4 vCPU
ARM64ab v18.1/v18.2 offiziell multi-arch

Verifizieren:

docker compose ps
NAME            IMAGE                           STATUS          PORTS
gitlab          gitlab/gitlab-ce:17.11.0-ce.0   Up 5 minutes    0.0.0.0:443->443/tcp, 0.0.0.0:2424->22/tcp, 0.0.0.0:8929->8929/tcp
gitlab-runner   gitlab/gitlab-runner:latest     Up 5 minutes

Sobald GitLab vollständig gestartet ist:

curl -I http://localhost:8929

Erwartetes Ergebnis: HTTP/1.1 302 Found mit Location: http://HOSTNAME:8929/users/sign_in.

Schritt 5: Erst-Einrichtung im Browser und Root-Passwort sichern

Rufe http://HOSTNAME:8929 im Browser auf. GitLab leitet auf die Login-Seite weiter. Melde dich mit Benutzername root und dem in der .env gesetzten Passwort an.

Falls du das Root-Passwort nicht über GITLAB_OMNIBUS_CONFIG gesetzt hast oder es auslesen möchtest:

docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

Wichtig: Diese Datei wird nach 24 Stunden automatisch gelöscht. Sichere das Passwort sofort.

Nach dem ersten Login empfiehlt sich die folgende Grundkonfiguration in der Admin-Oberfläche (Admin Area):

  1. Sign-up deaktivieren (Admin Area → Settings → General → Sign-up restrictions → Deactivate), damit sich keine unbekannten Nutzer registrieren können.
  2. E-Mail-Benachrichtigungen: SMTP-Einstellungen in GITLAB_OMNIBUS_CONFIG ergänzen, da GitLab keinen eingebauten Mailserver mitbringt.
  3. Root-Passwort ändern: Admin Area → Edit Profile → Password.

Verifizieren: Login mit root funktioniert, Dashboard lädt ohne Fehler, Admin Area ist erreichbar unter http://HOSTNAME:8929/admin.

Schritt 6: GitLab Runner registrieren für CI/CD-Pipelines

Der GitLab-Runner-Container läuft bereits (seit Schritt 4), ist aber noch nicht mit der GitLab-Instanz verbunden. CI/CD-Jobs bleiben solange in der Queue, bis ein Runner registriert ist. Hole zuerst das Registrierungs-Token aus der GitLab-UI:

  1. Admin Area → CI/CD → Runners → „Register an instance runner" → Token kopieren

Dann registriere den Runner im Container:

docker exec -it gitlab-runner gitlab-runner register

Der Befehl stellt interaktiv folgende Fragen:

Enter the GitLab instance URL:
# Eingabe: http://gitlab.example.com:8929

Enter the registration token:
# Eingabe: dein-token-aus-der-ui

Enter a description for the runner:
# Eingabe: docker-runner

Enter tags for the runner (comma-separated):
# Eingabe: docker (oder leer lassen)

Enter an executor:
# Eingabe: docker

Enter the default Docker image:
# Eingabe: alpine:latest

Nach erfolgreicher Registrierung speichert der Runner seine Konfiguration unter ${GITLAB_HOME}/runner/config/config.toml im persistenten Volume.

Verifizieren:

docker compose logs gitlab-runner | tail -20

Erwartetes Ergebnis: keine ERROR-Zeilen; im GitLab-Dashboard unter Admin Area → CI/CD → Runners erscheint der Runner mit grünem Status-Punkt. Lege 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)

GitLab CE enthält eine vollständige Container-Registry, die standardmäßig deaktiviert ist. Zur Aktivierung ergänze in der compose.yaml den Eintrag in GITLAB_OMNIBUS_CONFIG und ein zusätzliches 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'
      - '443:443'
      - '2424:22'
      - '5050:5050'

Anschließend den Stack neu starten:

cd /opt/gitlab-compose
docker compose up -d

Verifizieren:

curl -I http://localhost:5050/v2/

Erwartetes Ergebnis: HTTP/1.1 401 Unauthorized – das ist korrekt und zeigt, dass die Registry läuft und eine Authentifizierung erwartet. Login mit: docker login HOSTNAME:5050 und GitLab-Zugangsdaten.

Schritt 8: Updates und Backups

Updates durchführen

GitLab erlaubt keine direkten Sprünge über mehrere Major-Versionen (z. B. nicht von 16.x direkt auf 18.x). Immer den offiziellen Upgrade-Pfad unter docs.gitlab.com/update/upgrade_paths/ prüfen. Für Minor-Updates (z. B. 17.10.x → 17.11.x) ist das Vorgehen einfach:

# 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 -d

Datenbankmigrationen laufen automatisch beim Start; der Container ist für 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 /dein/backup-ziel/gitlab-secrets.json

Die Backup-Datei liegt unter /srv/gitlab/data/backups/ und kann auf externen Speicher (z. B. S3) übertragen werden. Wie du eine robuste Backup-Strategie mit Off-Site-Replikation aufbaust, 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

  1. „writing value to /dev/shm/gitlab/sidekiq/gauge... failed with unmapped file"shm_size: '256m' fehlt in der compose.yaml. Ergänzen und Container neu starten: docker compose up -d.
  2. Falsche Clone-URLs (falscher Port oder Hostname) – Port in external_url stimmt nicht mit dem gemappten Host-Port überein. In GITLAB_OMNIBUS_CONFIG muss external_url 'http://HOSTNAME:8929' exakt zu ports: - '8929:8929' passen.
  3. „502 Whoops" nach dem ersten Start – Kein Fehler; GitLab initialisiert sich noch. 3–5 Minuten warten und Logs beobachten: docker compose logs -f gitlab | grep -i booted.
  4. Root-Passwort verloren / initial_root_password-Datei weg – Die Datei wird nach 24 Stunden gelöscht. Passwort-Reset via Rails-Konsole: docker exec -it gitlab gitlab-rails consoleuser = User.find_by(username: 'root'); user.password = 'NeuesPasswort12!'; user.save!
  5. CI/CD-Jobs warten endlos in der Queue – Runner nicht registriert oder falsche GitLab-URL beim Register-Befehl angegeben. Schritt 6 wiederholen; docker compose logs gitlab-runner auf Verbindungsfehler prüfen.
  6. Container startet nicht, „ThreadError: Operation not permitted" – Docker-Version zu alt (vor 20.10.10). Docker aktualisieren: apt-get upgrade docker-ce docker-ce-cli containerd.io.
  7. OOM-Killer beendet Prozesse, zufällige Abstürze – Zu wenig RAM. GitLab braucht mindestens 4 GB allein für sich. Mit docker stats gitlab prüfen, ob der Container nahe am Speicherlimit arbeitet.
  8. Host-Festplatte läuft voll – Docker-Log-Rotation nicht konfiguriert. Die logging-Sektion mit max-size: '50m', max-file: '5' ist in der obigen compose.yaml bereits enthalten – sicherstellen, dass sie vorhanden ist.
  9. Upgrade schlägt fehl, Datenbank korrupt – Major-Versions-Sprung ü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?

Der erste Start dauert typischerweise 3–5 Minuten, auf langsamerer Hardware bis zu 10 Minuten. Während der Initialisierung zeigt GitLab „502 Whoops, GitLab is taking too much time to respond" – das ist normales Verhalten. Mit docker compose logs -f gitlab | grep -i 'server booted' kannst du den Abschluss der Initialisierung abwarten.

Wie unterscheidet sich GitLab CE von GitLab EE?

Beide basieren auf identischer Omnibus-Technik. Die Community Edition (CE) ist MIT-lizenziert und enthält alle Kernfunktionen: Git-Hosting, Merge Requests, integrierte CI/CD, SAST/DAST-Scanning, Container-Registry, Issue-Tracking, Wiki und Package-Registry. In der CE-Version fehlen im Vergleich zur Enterprise Edition primär: erweitertes Security-Dashboard, SAML SSO, GitLab Geo (Geo-Replikation) und erweiterte Compliance-Features. Für die meisten KMU und Teams bis ~100 Entwickler ist CE vollständig ausreichend.

Funktioniert GitLab CE auf ARM64-Servern?

Ab GitLab-Version 18.1/18.2 (erschienen 2025) gibt es offizielle Multi-Arch-Images (amd64 + arm64) unter gitlab/gitlab-ce – Docker wählt automatisch die passende Architektur. Für ältere Versionen (≤ 17.x) sind nur Community-Images verfügbar (yrzr/gitlab-ce-arm64v8), die jedoch veraltet sein können. Raspberry Pi 4/5 mit 4 GB+ RAM ist technisch möglich, aber ressourcenintensiv.

Wie richte ich HTTPS ein?

Es gibt zwei Wege: SSL direkt im GitLab-Container über Let's Encrypt (in GITLAB_OMNIBUS_CONFIG: letsencrypt['enable'] = true – erfordert öffentlich erreichbaren Port 80) oder HTTPS-Terminierung über einen vorgelagerten Reverse Proxy wie Caddy oder Nginx, der Anfragen an den internen Port 8929 weiterleitet. Die Reverse-Proxy-Variante ist für Server mit mehreren Diensten die sauberere Lösung.

Wie führe ich ein Backup durch?

Backup-Befehl: docker exec -t gitlab gitlab-backup create. Das Backup enthält alle Repositories, Issues, Merge Requests und CI/CD-Konfigurationen. Zusätzlich muss ${GITLAB_HOME}/config/gitlab-secrets.json manuell gesichert werden – dieser wird vom Backup-Kommando ausdrücklich nicht eingeschlossen. Verlust der Secrets-Datei macht alle CI/CD-Variablen und 2FA-Tokens unzugänglich.

Wie aktualisiere ich GitLab auf eine neue Version?

1. Backup erstellen (gitlab-backup create + gitlab-secrets.json sichern). 2. In compose.yaml den Image-Tag auf die Zielversion ändern – dabei keine Major-Versionen überspringen. 3. docker compose pull && docker compose up -d. 4. Datenbankmigrationen laufen automatisch beim Start. Den offiziellen Upgrade-Pfad immer vorab unter docs.gitlab.com/update/upgrade_paths/ prüfen.

Warum braucht GitLab keinen separaten Datenbank-Container?

GitLab CE verwendet eine Omnibus-Distribution: PostgreSQL, Redis, Sidekiq, Puma (Ruby on Rails), Nginx und Prometheus sind alle im einzigen Container gebündelt. Das vereinfacht den Betrieb erheblich, ist aber auch der Grund für den hohen Ressourcenbedarf. Ein separater PostgreSQL-Container ist zwar technisch möglich, aber offiziell nicht unterstützt.

Fazit

GitLab CE ist die vollständigste selbst gehostete DevOps-Plattform, die du als einzelnen Docker-Container betreiben kannst. Mit Git-Hosting, integrierten CI/CD-Pipelines, Container-Registry und Security-Scanning in einer Instanz ersetzt sie mehrere separate SaaS-Dienste – und das kostenlos unter MIT-Lizenz. Der Preis dafür ist ein ehrlicher: mindestens 4 GB RAM, eine gut geführte Upgrade-Strategie ohne Major-Versions-Sprünge und die Disziplin, gitlab-secrets.json bei jedem Upgrade zu sichern. Wer diese Anforderungen akzeptiert, bekommt eine stabile, datenschutzkonforme DevOps-Plattform, die mit dem Team skaliert.

Für Teams, die eine schlankere Git-Alternative suchen, lohnt ein Blick auf Gitea mit Docker: eigener Git-Server als GitHub-Alternative – ohne eingebettete CI/CD, dafür mit deutlich geringerem Ressourcenverbrauch.

Weiterführende Anleitungen und Quellen

  1. Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
  2. Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS
  3. Gitea mit Docker: eigener Git-Server als GitHub-Alternative
  4. 3-2-1-Backup-Strategie umsetzen: Restic, USB-Disk und S3-Cloud
  5. 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