Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Sicherheit & Datenschutz 09.10.2026 · 10 min Lesezeit

Warpgate mit Docker Compose: SSH-, HTTP- und Datenbank-Bastion ohne Client-Agent

Warpgate leitet SSH-, HTTP-, MySQL- und PostgreSQL-Verbindungen über einen zentralen Bastion-Host, ohne Software auf den Clients. Die Anleitung zeigt Einrichtung mit Docker Compose, Ziele, Rollen, Backup, Restore und Update.

Geprüft am 09.10.2026 · für Warpgate 0.29.2, PostgreSQL 17.11

Mit KI erstellt – redaktionelle Prüfung ausstehend

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

Hero-Grafik: Warpgate als Bastion-Host mit SSH, HTTP und Datenbank

Verteilte SSH-Schlüssel, offene Datenbank-Ports und VPN-Konten, die niemand mehr überblickt: Warpgate ersetzt das durch einen einzelnen Bastion-Host, der SSH, HTTP(S), MySQL, PostgreSQL, Kubernetes, RDP und VNC weiterreicht, Benutzer zentral prüft und Sitzungen aufzeichnet. Auf den Clients läuft nichts Zusätzliches, Admins nutzen ssh, psql oder den Browser. Diese Anleitung richtet Warpgate 0.29.2 mit Docker Compose ein, bindet ein SSH-, ein Web- und ein PostgreSQL-Ziel an und zeigt Rollen, Backup, Restore und Update.

Voraussetzungen

Warpgate ist schlank: Nach Einrichtung, drei Zielen und einigen Sitzungen belegte das Datenverzeichnis im Test 4,5 MB.

  • Linux-Server mit Docker Engine und Compose v2, 2 CPU-Kerne und 2 GB RAM inklusive Testzielen.
  • x86_64 oder ARM64: Das Image ghcr.io/warp-tech/warpgate wird für linux/amd64 und linux/arm64 gebaut.
  • Ein DNS-Name wie bastion.example.de; er bestimmt die Cookie-Domain (Schritt 3).
  • Freie Ports: 8888 (Weboberfläche und HTTP-Ziele, nur HTTPS), 2222 (SSH) und 55432 (PostgreSQL). MySQL nutzt 33306, Kubernetes 8443, RDP 3389 und VNC 5900, jeweils nur wenn bei der Einrichtung aktiviert.
  • Netzwerkzugriff vom Warpgate-Host auf die internen Ziele, die selbst nicht öffentlich erreichbar sein müssen.
  • Speicherplatz für Sitzungsaufzeichnungen unter /data/recordings.

Schritt 1: Projektordner, compose.yaml und .env anlegen

Am 09.10.2026 zeigten die Tags 0.29.2, 0.29 und latest auf denselben Digest. Pinnen Sie trotzdem die volle Version, damit Updates bewusst passieren. Der GitHub-Release heißt v0.29.2, der Image-Tag hat kein v.

mkdir -p /opt/warpgate/data && cd /opt/warpgate
# Das Image läuft als Benutzer warpgate mit UID 1000
chown 1000:1000 data

Die compose.yaml enthält Warpgate und drei Testziele ohne eigene Ports: OpenSSH, einen kleinen Webdienst und PostgreSQL 17. Sie sind nur über Warpgate erreichbar.

services:
  warpgate:
    image: ghcr.io/warp-tech/warpgate:${WARPGATE_VERSION:-0.29.2}
    restart: unless-stopped
    environment:
      WARPGATE_ADMIN_PASSWORD: ${WARPGATE_ADMIN_PASSWORD:?Admin-Passwort in .env setzen}
    ports:
      - "8888:8888"
      - "2222:2222"
      - "55432:55432"
    volumes:
      - ./data:/data
    stdin_open: true
    tty: true

  # Testziele für den ersten Durchlauf, später durch echte Server ersetzen
  ssh-ziel:
    image: lscr.io/linuxserver/openssh-server:latest
    environment:
      PUID: "1000"
      PGID: "1000"
      USER_NAME: deploy
      PASSWORD_ACCESS: "true"
      USER_PASSWORD: ${ZIEL_SSH_PASSWORT:?}
  web-ziel:
    image: traefik/whoami:latest
  db-ziel:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${ZIEL_DB_PASSWORT:?}
      POSTGRES_DB: app

Die .env im selben Ordner (Rechte 600). Die Beispielwerte sind Platzhalter:

WARPGATE_VERSION=0.29.2
WARPGATE_ADMIN_PASSWORD=bitte-langes-zufallspasswort-setzen
ZIEL_SSH_PASSWORT=nur-fuer-das-testziel
ZIEL_DB_PASSWORT=nur-fuer-das-testziel

Verifizieren: docker compose config --quiet läuft ohne Ausgabe durch. Fehlt das Admin-Passwort, bricht Compose ab mit required variable WARPGATE_ADMIN_PASSWORD is missing a value: Admin-Passwort in .env setzen.

Schritt 2: Warpgate einrichten und starten

Ohne Einrichtung endet der Container in einer Neustartschleife mit configuration file "/data/warpgate.yaml" not found. Statt des interaktiven setup nutzen Sie unattended-setup, das das Admin-Passwort aus WARPGATE_ADMIN_PASSWORD liest:

docker compose run --rm warpgate unattended-setup \
  --data-path /data \
  --http-port 8888 \
  --ssh-port 2222 \
  --postgres-port 55432 \
  --record-sessions \
  --external-host bastion.example.de
docker compose up -d

Der Assistent schreibt /data/warpgate.yaml, legt die SQLite-Datenbank unter /data/db/, ein selbstsigniertes TLS-Zertifikat, SSH-Schlüssel und den Benutzer admin an. Für MySQL ergänzen Sie --mysql-port 33306 samt Port-Mapping.

Verifizieren: docker compose logs warpgate zeigt Warpgate version=v0.29.2 und je eine Zeile Binding listener für SSH, HTTP und PostgreSQL. docker compose ps meldet nach wenigen Sekunden healthy; das Image bringt mit warpgate healthcheck einen eigenen Healthcheck mit. curl -k -o /dev/null -w "%{http_code}" https://localhost:8888/@warpgate liefert 200.

Schritt 3: Anmelden und den Hostnamen richtig setzen

Die Oberfläche liegt unter https://bastion.example.de:8888/@warpgate, die Verwaltung unter /@warpgate/admin. Port 8888 spricht nur HTTPS; curl http://localhost:8888/ endet mit Received HTTP/0.9 when not allowed.

Wichtiger ist der Hostname: Warpgate setzt das Sitzungs-Cookie für die Domain aus external_host (Log: Cookie domain configured: .bastion.example.de). Im Test lieferte die Anmeldung über einen anderen Namen 201, jede folgende Anfrage aber 401. Rufen Sie Warpgate deshalb immer über den eingetragenen Namen auf, nie per IP. Geändert wird der Wert in data/warpgate.yaml mit anschließendem Neustart.

Verifizieren: Die Anmeldung als admin führt in die Verwaltung; unter Config sind Targets, Users, Access roles und Admin roles sichtbar.

Schritt 4: SSH-, HTTP- und PostgreSQL-Ziele anlegen

Unter Config, Targets, Add a target legen Sie je Ziel einen Namen, den Typ und die Verbindungsdaten an. Für die Testziele:

  • ssh-ziel (SSH): Host ssh-ziel, Port 2222, Benutzer deploy, Passwort aus der .env. Für echte Server empfiehlt die Doku Warpgates öffentliche Schlüssel aus Config, SSH keys in der authorized_keys des Zielbenutzers.
  • web-ziel (HTTP): URL http://web-ziel:80, TLS-Modus Disabled.
  • db-ziel (PostgreSQL): Host db-ziel, Port 5432, Benutzer app mit Passwort aus der .env.
Warpgate-Verwaltung mit der Zielliste db-ziel (PostgreSQL), ssh-ziel (SSH) und web-ziel (HTTP) und dem Config-Menü links
Die drei Testziele in der Warpgate-Verwaltung unter Config, Targets.

Standardmäßig liegen Zielpasswörter im Klartext in der Datenbank. Seit 0.28 verschlüsselt sie WARPGATE_ENCRYPTION_KEY (aus openssl rand -base64 32). Warpgate speichert den Schlüssel nirgends; geht er verloren, sind alle Zielpasswörter neu einzugeben.

Verifizieren: Die Zielliste zeigt alle drei Einträge mit dem richtigen Protokoll.

Schritt 5: Rollen und Benutzer anlegen

Zugriffsrollen (Access roles) legen fest, welche Ziele ein Benutzer erreicht; Admin-Rollen geben Teilrechte in der Verwaltung. Legen Sie die Zugriffsrolle betrieb an, aktivieren Sie sie bei allen Zielen unter „Allow access for roles“ und weisen Sie sie dem neuen Benutzer lisa mit eigenem Passwort zu.

Einstellungen des SSH-Ziels ssh-ziel mit Host, Port 2222, Benutzer deploy, maskiertem Passwort und aktivierter Zugriffsrolle betrieb
SSH-Ziel mit gespeichertem Host-Schlüssel und freigeschalteter Rolle betrieb; die Rolle admin bleibt aus.

Gegenprobe: Ein Benutzer gast ohne Rolle bekam beim SSH-Ziel Permission denied (publickey,keyboard-interactive), im Log steht der Grund Target ssh-ziel not authorized for user gast. Die Verwaltungs-API antwortet lisa ohne Admin-Rolle mit 401.

Verifizieren: Nach der Anmeldung als lisa zeigt die Startseite genau die freigegebenen Ziele.

Schritt 6: Über Warpgate verbinden

Der Zielname steckt im Benutzernamen. Für SSH trennt ein Doppelpunkt Benutzer und Ziel, für Datenbanken wahlweise # oder ::

ssh -p 2222 lisa:ssh-ziel@bastion.example.de
psql "host=bastion.example.de port=55432 user=lisa#db-ziel dbname=app sslmode=require"
# HTTP-Ziel im Browser
https://bastion.example.de:8888/?warpgate-target=web-ziel

Beim ersten SSH-Zugriff fragt Warpgate: There is no trusted ssh-ed25519 key for this host. Trust this key? (y/n). Nach y speichert es den Schlüssel; prüfen Sie den Fingerabdruck. Abgefragt wird das Warpgate-Passwort von lisa, nicht das des Zielservers.

Warpgate-Dialog mit dem Beispielbefehl psql -U lisa#db-ziel --host server.example.de --port 55432 und dem Hinweis auf TLS
Für Datenbankziele zeigt Warpgate den passenden Client-Befehl samt Benutzerschreibweise an.

PostgreSQL nimmt Warpgate nur mit TLS an, sonst kommt FATAL: SSL connection required. Das HTTP-Ziel liefert ohne Anmeldung 401; danach reicht Warpgate Anfragen durch und ergänzt die Header X-Warpgate-Username und X-Warpgate-Authentication-Type.

Warpgate-Sitzungsprotokoll einer SSH-Sitzung von lisa auf ssh-ziel mit Anmeldung, ausgeführtem Befehl und Pfad der Aufzeichnung
Jede Sitzung erscheint unter Status, Sessions mit Anmeldung, Ziel, ausgeführten Befehlen und Aufzeichnung.

Verifizieren: ssh -p 2222 lisa:ssh-ziel@bastion.example.de hostname gibt den Hostnamen des Ziels aus, psql beantwortet select current_user; mit app, und unter Status, Sessions stehen die Verbindungen mit Benutzer, Ziel und Befehl.

Schritt 7: Reverse Proxy, TLS und Härtung

Das selbstsignierte Zertifikat ersetzen Sie in data/tls.certificate.pem und data/tls.key.pem oder setzen einen Reverse Proxy vor Port 8888. Im Test lief die Oberfläche hinter einem TLS-Proxy mit Ziel https://localhost:8888. Dazu gehört trust_x_forwarded_headers: true im Abschnitt http der warpgate.yaml; für das Web-Terminal braucht der Proxy Websockets:

location / {
    proxy_pass https://127.0.0.1:8888;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_http_version 1.1;
    proxy_read_timeout 3600s;
}

SSH und PostgreSQL laufen nicht über den HTTP-Proxy; öffnen Sie diese Ports nur für die Netze, die sie brauchen. Die Produktions-Checkliste des Projekts nennt zudem: eigenes Konto pro Admin, Zwei-Faktor-Pflicht (seit 0.29 global schaltbar), Login-Schutz gegen Brute Force und Admin-Freigabe für sensible Ziele.

Verifizieren: Der Aufruf über den Proxy-Namen zeigt ein gültiges Zertifikat, und nach der Anmeldung bleiben Verwaltung und Zielliste ohne erneute Abfrage erreichbar.

Schritt 8: Backup und Restore

Bei Docker mit SQLite liegen Konfiguration, Datenbank, Zertifikate und Aufzeichnungen in data; einen Verschlüsselungsschlüssel sichern Sie getrennt. Am einfachsten ist eine kalte Sicherung, denn die Datenbank läuft im WAL-Modus:

cd /opt/warpgate
docker compose exec warpgate warpgate version > backup/VERSION
docker compose stop warpgate
tar czf backup/warpgate-data-$(date +%F).tgz -C data .
docker compose start warpgate

Für den laufenden Betrieb nennt die Doku sqlite3 db.sqlite3 ".backup ...". Der Restore braucht dieselbe Warpgate-Version wie das Backup:

docker compose stop warpgate
mv data data.defekt && mkdir data
tar xzf backup/warpgate-data-2026-10-09.tgz -C data
chown -R 1000:1000 data
docker compose start warpgate

Im Test wurde vor der Sicherung ein Benutzer backup-marker angelegt, danach gelöscht und das Datenverzeichnis entfernt. Nach dem Restore war der Marker zurück, und SSH über Warpgate lief ohne erneute Host-Key-Rückfrage.

Verifizieren: docker compose exec warpgate sqlite3 /data/db/db.sqlite3 "select username from users;" listet alle Benutzer inklusive Marker, und eine Testverbindung zu einem SSH-Ziel gelingt.

Schritt 9: Update und Rollback

Ein Update ist ein Image-Tausch: Version in der .env anheben, docker compose pull, docker compose up -d; Migrationen laufen beim Start. Sichern Sie vorher, denn zurück geht es nur per Backup. Im Test hing 0.28.2 auf einer von 0.29.2 migrierten Datenbank in einer Neustartschleife mit Migration file of version 'm00087_drop_null_target_options' is missing, this migration has been applied but its file is missing. Mit 0.29.2 lief die Instanz sofort wieder.

Verifizieren: Nach dem Update nennt das Log die neue Version, docker compose ps meldet healthy und eine Testverbindung gelingt.

Troubleshooting

  • Neustartschleife mit configuration file "/data/warpgate.yaml" not found: Entweder fehlt die Einrichtung aus Schritt 2, oder das Datenverzeichnis gehört nicht UID 1000. Im Test löste ein root-eigenes, auf 700 gesetztes data genau diese irreführende Meldung aus. Abhilfe: chown -R 1000:1000 data.
  • Anmeldung klappt, danach sofort wieder abgemeldet: Der Aufrufname passt nicht zu external_host, das Cookie wird verworfen. Mit dem eingetragenen Namen aufrufen oder den Wert anpassen.
  • Permission denied, please try again. beim SSH-Login: falsches Warpgate-Passwort. Bei Permission denied (publickey,keyboard-interactive) nach erfolgreicher Anmeldung fehlt die Zugriffsrolle oder der Zielname ist falsch geschrieben.
  • SSL connection required bei psql: Im Client sslmode=require setzen.
  • driver failed programming external connectivity ... port is already allocated: Ein anderer Dienst belegt einen der veröffentlichten Ports. Dienst stoppen oder das linke Port-Mapping ändern, danach docker compose up -d --force-recreate warpgate.
  • Admin-Passwort vergessen: docker compose exec -it warpgate warpgate recover-access setzt laut Doku ein neues Passwort und deaktiviert die Zwei-Faktor-Pflicht für diesen Benutzer.

Häufige Fragen

Brauchen die Mitarbeitenden einen Client oder Agenten?

Nein. SSH, psql, mysql, kubectl und der Browser reichen. Für SSH und RDP gibt es zusätzlich Clients im Browser, die sich global abschalten lassen.

Worin unterscheidet sich Warpgate von JumpServer?

JumpServer ist eine umfangreiche PAM-Plattform aus mehreren Diensten, siehe unsere JumpServer-Anleitung. Warpgate ist ein einzelnes Programm mit SQLite und passt, wenn ein kleines Team schnell einen kontrollierten Einstiegspunkt braucht.

Ersetzt Warpgate ein VPN?

Für Admin-Zugriffe auf einzelne Dienste oft ja. Für vollen Netzzugriff bleibt ein VPN wie WireGuard mit wg-easy passender; kombiniert ist Warpgate nur aus dem VPN erreichbar.

Gibt es kostenpflichtige Funktionen?

Nein. Warpgate steht unter Apache-2.0; laut Projektseite kostet nur Support der Entwickler.

Sind die Befehlsprotokolle revisionssicher?

Nein. Die Doku nennt die Erkennung einzelner Shell-Befehle selbst eine Hilfe für das Audit und keine Sicherheitsgrenze. Die vollständige Aufzeichnung der Sitzung ist belastbarer als die Befehlsliste.

Warpgate entfernen

Warnung: Das folgende Vorgehen löscht Benutzer, Ziele, gespeicherte Zugangsdaten, Host-Schlüssel und alle Aufzeichnungen unwiderruflich. Sichern Sie vorher wie in Schritt 8 und entfernen Sie Warpgates öffentliche Schlüssel aus den authorized_keys der Zielserver.

cd /opt/warpgate
docker compose down
rm -rf /opt/warpgate/data

Fazit

Warpgate bringt zentrale Benutzer, Rollen und Sitzungsaufzeichnung ohne Client-Software in einen einzelnen Container. Im Test liefen SSH, HTTP und PostgreSQL nach wenigen Minuten, die Rollen griffen, und der Restore stellte alles wieder her. Beachten Sie drei Punkte: Der Hostname bestimmt die Cookie-Domain, data muss UID 1000 gehören, und ein Update ist ohne Backup eine Einbahnstraße.

EckdatenWert
Imageghcr.io/warp-tech/warpgate:0.29.2 (amd64, arm64)
Ports8888 HTTPS, 2222 SSH, 55432 PostgreSQL, optional 33306, 8443, 3389, 5900
Volume/data (Konfiguration, SQLite, TLS, Aufzeichnungen)
Benutzer im Containerwarpgate, UID 1000
Wichtige VariablenWARPGATE_ADMIN_PASSWORD (Einrichtung), WARPGATE_ENCRYPTION_KEY (optional)
Healthcheckim Image enthalten: warpgate healthcheck
LizenzApache-2.0

Weiterführende Anleitungen und Quellen

WarpgateBastion-HostSSHDocker ComposeZugriffskontrollePostgreSQLSelfhosting