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.

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
- 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
- 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
- Docker Engine 20.10+ mit Docker Compose v2 (Plugin, nicht das veraltete
docker-composev1) – falls noch nicht installiert, hilft die Anleitung Docker und Docker Compose auf Linux installieren - openssl zur Schlüsselgenerierung (auf allen gängigen Distributionen vorinstalliert)
- 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
- Mindestens 20 GB freier Speicherplatz für Repositories, Datenbank und Artifact-Registry
- 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/harnessWer 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:3000Den Schlüssel für HARNESS_SECRET_KEY erzeugst du einmalig per:
openssl rand -hex 16Kopiere 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: bridgeZwei 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:
| Parameter | Wert | Hinweis |
|---|---|---|
| Image | harness/harness:latest | Ehemals harness/gitness (veraltet seit v3.0) |
| Port 3000 | Web-UI, REST-API, Git-HTTP | Haupt-Einstiegspunkt |
| Port 3022 | SSH-Git-Zugriff | Optional, für git clone ssh://... |
Volume harness_data | /data im Container | Repos, Cache, Artifact-Registry |
Volume postgres_data | PostgreSQL-Datenbankdateien | Getrennt von Harness-Daten |
| Docker Socket | /var/run/docker.sock | Pflicht für CI/CD-Pipelines |
| Datenbank | PostgreSQL 16 | Standard wäre SQLite3 (nicht empfohlen) |
| Lizenz | Apache 2.0 | Kein 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 -dDocker 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 psErwartete 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=30Suche 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:3000Erwartete 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:
- Organisation anlegen: Unter „Organizations" eine neue Org für dein Team erstellen – Repositories, Pipelines und Einstellungen werden darunter gruppiert.
- 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.
- Clone-URL prüfen: Öffne ein Repository und kontrolliere die Clone-URL. Sie muss mit dem Wert von
HARNESS_URL_BASEbeginnen, nicht mithttp://localhost. Zeigt sielocalhost, stimmt die Variable nicht. - CI-Pipeline testen: Lege eine
.harness/pipeline.yamlim 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 -dFü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=20Beide Container zeigen Up, keine Fehlermeldungen zu Datenbankmigrationen in den Logs. Die Web-UI ist weiterhin erreichbar und zeigt die bisherigen Daten.
Troubleshooting / Typische Fehler
- Clone-URLs zeigen
localhoststatt Server-IP:GITNESS_URL_BASEist nicht gesetzt oder enthält noch den Platzhalterwert. In der.envaufhttp://DEINE-SERVER-IP:3000(oder die HTTPS-Domain) setzen, danndocker compose up -d– Harness liest die Variable beim Start neu ein. - CI/CD-Pipelines starten nicht / Steps erreichen Harness-API nicht:
GITNESS_URL_CONTAINERzeigt auflocalhoststatt auf den Container-Namenharness, oderGITNESS_CI_CONTAINER_NETWORKSist nicht auf das Compose-Netzwerk gesetzt. Beide Variablen wie in dercompose.yamloben konfigurieren. - Datenverlust nach Neustart: Quick-Start-Beispiele aus der offiziellen Doku nutzen
/tmp/harnessals Bind-Mount –/tmpwird auf vielen Systemen beim Reboot geleert. Immer ein Named Volume oder einen Pfad außerhalb/tmp(z.B./opt/harness/data) verwenden. permission deniedauf/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 derdocker-Gruppe auf dem Host sein.- Admin-Konto funktioniert nicht nach Passwort-Änderung in
.env:GITNESS_PRINCIPAL_ADMIN_EMAILundGITNESS_PRINCIPAL_ADMIN_PASSWORDwerden ausschließlich beim allerersten Start (leere Datenbank) ausgewertet. Passwort-Reset erfolgt über die Web-UI oder direkt in PostgreSQL. - PostgreSQL-Healthcheck schlägt fehl / Harness startet zu früh: Nur relevant, wenn du
depends_onohnecondition: service_healthyverwendest. Diecompose.yamlin dieser Anleitung enthält den korrekten Healthcheck – nicht vereinfachen. - 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. - Altes
harness/gitness-Image im Einsatz: Dieses Image erhielt seit v3.0.0-beta.12 keine Updates mehr. Ausschließlichharness/harness:latestverwenden. GITNESS_ENCRYPTER_SECRETnachträ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
- Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
- Caddy als Reverse Proxy mit automatischem HTTPS einrichten
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only
- 3-2-1-Backup-Strategie umsetzen mit Restic, USB-Disk und S3-Cloud
- Docker-Container automatisch aktualisieren: Diun, WUD und Renovate im Vergleich
- 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.