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

Harness Open Source mit Docker installieren: End-to-End-DevOps-Plattform mit Git, CI/CD und Artifact-Registry

Harness Open Source vereint Git-Hosting, CI/CD-Pipelines und Artifact-Registry in einem Docker-Container. Diese Anleitung zeigt den produktionsreifen Aufbau mit Docker Compose und PostgreSQL – inklusive aller kritischen Variablen und Stolperfallen.

Harness Open Source mit Docker installieren: End-to-End-DevOps-Plattform mit Git-Integration, CI/CD-Pipelines, Artifact-Registry, Deployments, Sicherheitskontrolle und Server-Infrastruktur. KI-generiert

Wer einen selbst gehosteten DevOps-Stack betreiben will, steht vor einer klassischen Entscheidung: Gitea für Git-Hosting, Jenkins oder Drone für CI/CD, eine separate Artifact-Registry für Container-Images – oder alles in einem. Harness Open Source (bis Version 3.0 unter dem Namen Gitness bekannt) geht den zweiten Weg konsequent: Die Plattform bündelt Git-Hosting mit Code-Review und Vulnerability-Scanning, CI/CD-Pipelines mit wiederverwendbaren Templates, sogenannte Gitspaces als vorkonfigurierte Dev-Environments und eine Artifact-Registry für Container-Images und andere Artefakte – alles in einem einzigen Docker-Image. Mit 36.700 GitHub-Stars (Stand Juni 2026), Apache-2.0-Lizenz und aktivem Entwicklungstakt ist sie eine ernsthafte Alternative zu GitHub/GitLab für Teams, die keinen Cloud-Zwang mögen.

Voraussetzungen

  1. Linux-Host oder VM (x86_64 oder arm64): Ubuntu 22.04/24.04, Debian 12 oder vergleichbar; läuft ebenso auf einem NAS mit Docker-Unterstützung
  2. Ressourcen: mindestens 2 CPU-Kerne und 2 GB RAM für den Basis-Betrieb; für aktive CI/CD-Workloads empfehlen sich 4 Kerne und 4–8 GB RAM, da Pipeline-Container direkt auf dem Host-Docker laufen
  3. Docker Engine 20.10+ mit Docker Compose v2 (Plugin, nicht das veraltete docker-compose v1) – falls noch nicht installiert, hilft die Anleitung Docker und Docker Compose auf Linux installieren
  4. openssl zur Schlüsselgenerierung (auf allen gängigen Distributionen vorinstalliert)
  5. Ports 3000 und 3022 in deiner Firewall/Security-Group freigegeben: 3000 für Web-UI, REST-API und Git-HTTP, 3022 für SSH-Git-Zugriff
  6. Mindestens 20 GB freier Speicherplatz für Repositories, Datenbank und Artifact-Registry
  7. Optional: Domain und Reverse Proxy (Nginx, Caddy, Traefik) für HTTPS – siehe Caddy als Reverse Proxy mit automatischem HTTPS

Schritt 1: Projektordner anlegen

Lege einen dedizierten Ordner für den Harness-Stack an. Alle Konfigurationsdateien gehören dort hinein:

sudo mkdir -p /opt/harness
cd /opt/harness

Wer keinen root-Zugriff hat oder lieber im Home-Verzeichnis arbeitet, kann auch ~/harness verwenden – die Compose-Konfiguration funktioniert in beiden Fällen identisch.

Verifizieren: ls -la /opt/harness zeigt das leere Verzeichnis. Der Ordner muss existieren, bevor du die nächsten Dateien anlegst.

Schritt 2: .env-Datei mit Secrets befüllen

Die .env-Datei enthält alle sensitiven Werte. Docker Compose liest sie automatisch ein, wenn sie im selben Verzeichnis wie die compose.yaml liegt. Erstelle sie mit folgendem Inhalt – passe die markierten Werte an:

# Harness Open Source – Umgebungsvariablen
# /opt/harness/.env

# Admin-Konto (NUR beim allerersten Start mit leerer DB wirksam!)
HARNESS_ADMIN_EMAIL=admin@example.com
HARNESS_ADMIN_PASSWORD=SicheresPasswort123!

# AES-Verschlüsselungsschlüssel für Connector-Secrets in der DB
# Generieren: openssl rand -hex 16
# ACHTUNG: Diesen Wert nach dem ersten Start NIEMALS ändern!
HARNESS_SECRET_KEY=dein-16-byte-hex-schluessel

# PostgreSQL-Datenbankpasswort
POSTGRES_PASSWORD=SicheresDBPasswort456!

# Öffentlich erreichbare URL deines Servers (KEIN trailing slash)
# Für lokalen Test: http://localhost:3000
# Für Remote-Zugriff: http://DEINE-SERVER-IP:3000
# Hinter Reverse Proxy: https://git.example.com
HARNESS_URL_BASE=http://DEINE-SERVER-IP:3000

Den Schlüssel für HARNESS_SECRET_KEY erzeugst du einmalig per:

openssl rand -hex 16

Kopiere die Ausgabe direkt in die .env-Datei. Dieser Wert darf später nicht mehr verändert werden – sonst können gespeicherte Connector-Secrets (z.B. GitHub-Tokens) nicht mehr entschlüsselt werden.

Verifizieren: cat /opt/harness/.env zeigt alle fünf Variablen ohne Leerzeilen oder Sonderzeichen-Fehler. Stelle sicher, dass die Datei nur für den eigenen User lesbar ist: chmod 600 /opt/harness/.env.

Schritt 3: compose.yaml erstellen

Die folgende Konfiguration startet Harness zusammen mit einer PostgreSQL 16-Datenbank. Der depends_on-Block mit condition: service_healthy stellt sicher, dass Harness erst startet, wenn PostgreSQL wirklich bereit ist – ein wichtiger Unterschied zum einfachen depends_on ohne Health-Bedingung.

services:
  harness:
    image: harness/harness:latest
    container_name: harness
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "3000:3000"
      - "3022:3022"
    volumes:
      - harness_data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - GITNESS_PRINCIPAL_ADMIN_EMAIL=${HARNESS_ADMIN_EMAIL:-admin@example.com}
      - GITNESS_PRINCIPAL_ADMIN_PASSWORD=${HARNESS_ADMIN_PASSWORD}
      - GITNESS_ENCRYPTER_SECRET=${HARNESS_SECRET_KEY}
      - GITNESS_DATABASE_DRIVER=postgres
      - GITNESS_DATABASE_DATASOURCE=host=db port=5432 sslmode=disable dbname=harness user=harness password=${POSTGRES_PASSWORD}
      - GITNESS_URL_BASE=${HARNESS_URL_BASE:-http://localhost:3000}
      - GITNESS_URL_CONTAINER=http://harness:3000
      - GITNESS_URL_REGISTRY=http://harness:3000
      - GITNESS_CI_CONTAINER_NETWORKS=harness_network
      - GITNESS_CI_PARALLEL_WORKERS=2
      - GITNESS_USER_SIGNUP_ENABLED=false
    networks:
      - harness_network

  db:
    image: postgres:16-alpine
    container_name: harness_db
    restart: unless-stopped
    environment:
      - POSTGRES_DB=harness
      - POSTGRES_USER=harness
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U harness -d harness"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - harness_network

volumes:
  harness_data:
  postgres_data:

networks:
  harness_network:
    driver: bridge

Zwei Punkte verdienen besondere Aufmerksamkeit: Der Docker-Socket /var/run/docker.sock ist Pflicht, damit CI/CD-Pipelines und Gitspaces Container auf dem Host starten können. Die Variable GITNESS_CI_CONTAINER_NETWORKS=harness_network sorgt dafür, dass diese Pipeline-Step-Container ebenfalls im selben Netzwerk landen und die Harness-API über GITNESS_URL_CONTAINER=http://harness:3000 erreichen können.

Zu GITNESS_USER_SIGNUP_ENABLED=false: In einer produktiven Umgebung solltest du die offene Selbstregistrierung deaktivieren. Neue Nutzer legst du dann manuell über die Web-UI oder API an.

Die wichtigsten Stack-Parameter auf einen Blick:

ParameterWertHinweis
Imageharness/harness:latestEhemals harness/gitness (veraltet seit v3.0)
Port 3000Web-UI, REST-API, Git-HTTPHaupt-Einstiegspunkt
Port 3022SSH-Git-ZugriffOptional, für git clone ssh://...
Volume harness_data/data im ContainerRepos, Cache, Artifact-Registry
Volume postgres_dataPostgreSQL-DatenbankdateienGetrennt von Harness-Daten
Docker Socket/var/run/docker.sockPflicht für CI/CD-Pipelines
DatenbankPostgreSQL 16Standard wäre SQLite3 (nicht empfohlen)
LizenzApache 2.0Kein Cloud-Zwang, kein Telemetrie-Pflicht

Verifizieren: Prüfe die Syntax vor dem Start:

docker compose -f /opt/harness/compose.yaml config --quiet && echo "Syntax OK"

Die Ausgabe Syntax OK bestätigt eine valide YAML-Struktur. Fehlende .env-Werte werden hier als Warnung angezeigt.

Schritt 4: Stack starten

Wechsle in den Projektordner und starte den Stack:

cd /opt/harness
docker compose up -d

Docker zieht beide Images (harness/harness:latest und postgres:16-alpine), erstellt die Named Volumes und das Bridge-Netzwerk, wartet auf den PostgreSQL-Healthcheck und startet danach Harness. Beim allerersten Start legt Harness alle Datenbanktabellen an und erstellt das Admin-Konto aus den .env-Variablen.

Verifizieren: Prüfe den Status beider Container:

docker compose ps

Erwartete Ausgabe (beide Container Up, db mit healthy):

NAME          IMAGE                    STATUS
harness       harness/harness:latest   Up About a minute
harness_db    postgres:16-alpine       Up About a minute (healthy)

Zeige die Logs von Harness, um den Startvorgang zu beobachten:

docker compose logs harness --tail=30

Suche nach einer Zeile wie server listening on :3000 oder started – das signalisiert einen erfolgreichen Start. Fehlermeldungen zu Datenbankverbindungen deuten auf ein Problem mit der .env oder dem PostgreSQL-Container hin.

Abschließend per HTTP-Check:

curl -I http://localhost:3000

Erwartete Antwort: HTTP/1.1 200 OK oder 302 Found (Redirect zur Login-Seite).

Schritt 5: Erst-Einrichtung im Browser

Öffne http://DEINE-SERVER-IP:3000 im Browser. Du wirst zur Login-Seite weitergeleitet. Melde dich mit der E-Mail und dem Passwort an, die du in der .env-Datei hinterlegt hast.

Nach dem Login empfehlen sich folgende erste Schritte in der Web-UI:

  1. Organisation anlegen: Unter „Organizations" eine neue Org für dein Team erstellen – Repositories, Pipelines und Einstellungen werden darunter gruppiert.
  2. Repository erstellen oder importieren: Über „New Repository" ein frisches Repo anlegen oder über „Import Repository" ein bestehendes von GitHub/GitLab mit kompletter Code-History importieren – kein externes CLI nötig.
  3. Clone-URL prüfen: Öffne ein Repository und kontrolliere die Clone-URL. Sie muss mit dem Wert von HARNESS_URL_BASE beginnen, nicht mit http://localhost. Zeigt sie localhost, stimmt die Variable nicht.
  4. CI-Pipeline testen: Lege eine .harness/pipeline.yaml im Repository an und triggere sie manuell – das testet gleichzeitig die Docker-Socket-Integration und das Netzwerk-Routing der Pipeline-Steps.

Verifizieren: Navigiere im Browser zu http://DEINE-SERVER-IP:3000/api/v1/system/health. Die API gibt einen JSON-Response zurück, der den Systemstatus bestätigt. Eine erfolgreiche Anmeldung und das Erscheinen der Dashboard-Übersicht zeigen, dass das Admin-Konto korrekt angelegt wurde.

Schritt 6: Updates und Backups

Harness führt Datenbankmigrationen automatisch beim Start durch. Vor jedem Update solltest du dennoch ein Backup erstellen:

# Stack stoppen (Konsistenz-Sicherung)
cd /opt/harness
docker compose stop

# Harness-Daten sichern (Named Volume)
docker run --rm \
  -v harness_harness_data:/data \
  -v $(pwd)/backups:/backup \
  alpine tar czf /backup/harness-backup-$(date +%Y%m%d).tar.gz /data

# PostgreSQL-Dump
docker compose start db
docker exec harness_db pg_dump -U harness harness \
  > ./backups/harness-db-$(date +%Y%m%d).sql

# Stack neu starten und Image aktualisieren
docker compose pull
docker compose up -d

Für automatische Container-Update-Benachrichtigungen (ohne unkontrollierte Auto-Updates) eignet sich DIUN oder WUD – mehr dazu in der Anleitung Docker-Container automatisch aktualisieren nach dem Watchtower-Aus.

Eine strukturierte Backup-Strategie beschreibt 3-2-1-Backup-Strategie umsetzen.

Verifizieren: Nach dem Update:

docker compose ps
docker compose logs harness --tail=20

Beide Container zeigen Up, keine Fehlermeldungen zu Datenbankmigrationen in den Logs. Die Web-UI ist weiterhin erreichbar und zeigt die bisherigen Daten.

Troubleshooting / Typische Fehler

  1. Clone-URLs zeigen localhost statt Server-IP: GITNESS_URL_BASE ist nicht gesetzt oder enthält noch den Platzhalterwert. In der .env auf http://DEINE-SERVER-IP:3000 (oder die HTTPS-Domain) setzen, dann docker compose up -d – Harness liest die Variable beim Start neu ein.
  2. CI/CD-Pipelines starten nicht / Steps erreichen Harness-API nicht: GITNESS_URL_CONTAINER zeigt auf localhost statt auf den Container-Namen harness, oder GITNESS_CI_CONTAINER_NETWORKS ist nicht auf das Compose-Netzwerk gesetzt. Beide Variablen wie in der compose.yaml oben konfigurieren.
  3. Datenverlust nach Neustart: Quick-Start-Beispiele aus der offiziellen Doku nutzen /tmp/harness als Bind-Mount – /tmp wird auf vielen Systemen beim Reboot geleert. Immer ein Named Volume oder einen Pfad außerhalb /tmp (z.B. /opt/harness/data) verwenden.
  4. permission denied auf /var/run/docker.sock: Standardmäßig läuft Harness als Root, was ausreicht. Falls du die User-Isolation angepasst hast, muss der Container-User Mitglied der docker-Gruppe auf dem Host sein.
  5. Admin-Konto funktioniert nicht nach Passwort-Änderung in .env: GITNESS_PRINCIPAL_ADMIN_EMAIL und GITNESS_PRINCIPAL_ADMIN_PASSWORD werden ausschließlich beim allerersten Start (leere Datenbank) ausgewertet. Passwort-Reset erfolgt über die Web-UI oder direkt in PostgreSQL.
  6. PostgreSQL-Healthcheck schlägt fehl / Harness startet zu früh: Nur relevant, wenn du depends_on ohne condition: service_healthy verwendest. Die compose.yaml in dieser Anleitung enthält den korrekten Healthcheck – nicht vereinfachen.
  7. SSH-Port 3022 bereits belegt: Einen alternativen Host-Port wählen ("2222:3022") und den SSH-Client entsprechend konfigurieren: git clone ssh://git@SERVER-IP:2222/org/repo.
  8. Altes harness/gitness-Image im Einsatz: Dieses Image erhielt seit v3.0.0-beta.12 keine Updates mehr. Ausschließlich harness/harness:latest verwenden.
  9. GITNESS_ENCRYPTER_SECRET nachträglich gesetzt oder geändert: Alle bisher gespeicherten Connector-Secrets können danach nicht mehr entschlüsselt werden. Den Schlüssel beim ersten Start setzen und in einem Passwortmanager sichern.

Häufige Fragen

Brauche ich zwingend PostgreSQL, oder reicht SQLite?

SQLite (Standard ohne explizite GITNESS_DATABASE_DRIVER-Konfiguration) ist für Einzelpersonen und sehr kleine Teams mit bis zu etwa zehn aktiven Nutzern vollkommen ausreichend. Sobald mehrere Entwickler gleichzeitig Pushes und CI-Runs durchführen, erzeugt SQLite bei parallelen Schreibzugriffen Sperrkonflikte. Die Empfehlung für produktive Teams lautet daher: PostgreSQL von Anfang an, wie in dieser Anleitung gezeigt. Ein nachträglicher Wechsel erfordert eine manuelle Datenmigration.

Wie importiere ich bestehende Repositories von GitHub oder GitLab?

Harness Open Source bietet in der Web-UI unter „Import Repository" und „Import Organization" eine eingebaute Migrationsfunktion. Code-History, Branches und Tags werden vollständig übertragen. Je nach Quell-Provider können auch Issues und Pull-Requests importiert werden. Ein externes CLI oder Skript ist nicht nötig.

Wie funktioniert der Update-Prozess?

Ein Update läuft mit zwei Befehlen: docker compose pull && docker compose up -d. Harness führt Datenbankmigrationen automatisch beim nächsten Start durch. Lege vor jedem Update ein Volume-Backup an (siehe Schritt 6), um im Fehlerfall auf die vorherige Version rollback zu können.

Kann ich Harness hinter einem Reverse Proxy mit HTTPS betreiben?

Ja. Harness selbst terminiert kein TLS. Du stellst einen vorgelagerten Reverse Proxy (Nginx, Caddy, Traefik) bereit, der Port 443 auf Port 3000 weiterleitet, und setzt HARNESS_URL_BASE=https://git.example.com in der .env. Für SSH-Git-Zugriff muss Port 3022 separat erreichbar sein. Eine Schritt-für-Schritt-Anleitung für Caddy findest du unter Caddy als Reverse Proxy mit automatischem HTTPS.

Wie viele Ressourcen benötigt Harness im laufenden Betrieb?

Im Leerlauf ohne aktive Pipelines genügen 2 CPU-Kerne und 2 GB RAM. Sobald CI/CD-Pipelines laufen, starten die Steps als eigenständige Docker-Container direkt auf dem Host – deren Ressourcenbedarf addiert sich zum Harness-Prozess selbst. Für Teams mit mehreren gleichzeitigen Pipeline-Runs empfehlen sich 4 Kerne und 4–8 GB RAM. Den Wert GITNESS_CI_PARALLEL_WORKERS (Standard: 2) kannst du entsprechend der verfügbaren Kerne erhöhen.

Gibt es Telemetrie oder Cloud-Pflichtkomponenten?

Nein. Harness Open Source ist vollständig selbst gehostet ohne Cloud-Pflichtkomponenten. Der einzige externe Endpunkt ist ein Metriken-Reporting an stats.drone.ci, der auf Wunsch durch eine Firewall-Regel blockiert werden kann. Kein Account bei Harness SaaS nötig.

Fazit

Harness Open Source ist derzeit eine der vollständigsten Self-Hosted-DevOps-Plattformen auf dem Markt: Ein einziger Docker-Stack ersetzt Git-Server, CI-System und Artifact-Registry. Der Einstieg gelingt in unter 15 Minuten; die kritischen Konfigurationsvariablen – vor allem GITNESS_URL_BASE, GITNESS_URL_CONTAINER und GITNESS_ENCRYPTER_SECRET – bestimmen, ob der Betrieb später reibungslos läuft oder mit schwer nachvollziehbaren Fehlern kämpft. Die Entscheidung zwischen SQLite und PostgreSQL sollte von Anfang an zu Gunsten von PostgreSQL fallen, wenn mehr als eine Handvoll Nutzer aktiv sind. Wer eine sichere Docker-Compose-Umgebung aufbauen möchte, findet weitere Hinweise zu Secrets-Handling und Healthchecks in der Anleitung Docker Compose absichern: Secrets, Healthchecks, Non-Root.

Weiterführende Anleitungen und Quellen

  1. Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
  2. Caddy als Reverse Proxy mit automatischem HTTPS einrichten
  3. Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only
  4. 3-2-1-Backup-Strategie umsetzen mit Restic, USB-Disk und S3-Cloud
  5. Docker-Container automatisch aktualisieren: Diun, WUD und Renovate im Vergleich
  6. Gitea mit Docker: eigener Git-Server als GitHub-Alternative

Quellen: Harness Open Source auf GitHub (harness/harness) – offizielle Codebasis, Dockerfile, Releases; Harness Developer Hub – Quick Start; Harness Developer Hub – Konfigurationsreferenz (Settings); Harness Developer Hub – PostgreSQL-Konfiguration; Docker Hub – harness/harness.