Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Datenbanken 04.10.2026 · 10 min Lesezeit

DbGate mit Docker Compose selbst hosten und absichern

DbGate verwaltet PostgreSQL, MySQL, MariaDB, MongoDB, Redis und weitere Datenbanken im Browser. Die Anleitung zeigt eine getestete Installation von DbGate 7.3.1 mit Docker Compose, vorkonfigurierten Verbindungen per Umgebungsvariablen, erzwungener Anmeldung samt Negativtest, eingeschränktem Zweitkonto, Reverse Proxy mit TLS, Backup, Restore und Update.

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

Symbolbild: DbGate mit Docker Compose selbst hosten, Login und Backup

DbGate ist ein quelloffener Datenbank-Manager, der im Browser läuft und PostgreSQL, MySQL, MariaDB, SQL Server, MongoDB, Redis, SQLite und weitere Systeme unter einer Oberfläche bedient. Als Container auf einem Server ersetzt er verstreute Desktop-Clients: Verbindungen werden einmal zentral hinterlegt, Mitarbeitende und Dienstleister melden sich im Browser an und sehen nur, was ihnen freigegeben ist. Diese Anleitung zeigt eine getestete Installation von DbGate 7.3.1 mit Docker Compose, vorkonfigurierten Verbindungen zu PostgreSQL und MariaDB, Pflicht-Anmeldung, eingeschränktem Zweitkonto, Healthcheck, Reverse Proxy, Backup, Restore und Update.

Voraussetzungen

  • Server: Linux mit Docker und Compose-Plugin v2, 1 bis 2 CPU-Kerne.
  • Arbeitsspeicher: DbGate belegte im Test im Leerlauf rund 70 MB, PostgreSQL rund 100 MB, MariaDB rund 120 MB. Planen Sie 2 GB ein.
  • Speicher: Das Image ist entpackt rund 660 MB groß; dazu kommen die Datenbank-Volumes.
  • Architektur: Die Tags auf Docker Hub gibt es für amd64, arm64 und arm (32 Bit). Die -alpine-Varianten sind kleiner, unterstützen laut Image-Beschreibung aber kein SQLite.
  • Netz: Eine Subdomain mit TLS-Zertifikat am Reverse Proxy oder ein VPN wie WireGuard oder Tailscale. DbGate gehört nicht ungeschützt ins Internet.

Was DbGate leistet und wo die Grenzen liegen

DbGate besteht aus einer Node.js-API und einer Weboberfläche mit Datentabellen, SQL-Editor mit Autovervollständigung, Abfrage-Designer, ER-Diagrammen sowie Import und Export (CSV, JSON, Excel, SQL). Für Redis und MongoDB gibt es eigene Ansichten. Das unterscheidet DbGate von CloudBeaver mit Docker Compose: CloudBeaver braucht eine JVM, deckt relationale Datenbanken ab und richtet Konten im Browser ein. DbGate startet in Sekunden, spricht auch NoSQL und wird vollständig über Umgebungsvariablen konfiguriert. Das ist reproduzierbar, aber unbequemer: Benutzer und Verbindungen ändern Sie in der Community Edition nur in der compose.yaml.

Ehrlich zu den Editionen: Das Repository steht unter GPL-3.0, das Image dbgate/dbgate ist die kostenlose Community Edition ohne Lizenzschlüssel. Laut Vergleichstabelle des Herstellers sind Administrationsoberfläche, Benutzer- und Rollenverwaltung, rollenbasierter Zugriff auf Verbindungen sowie OAuth und Microsoft Entra der kostenpflichtigen Team Premium Edition (Image dbgate/dbgate-premium) vorbehalten. Die Doku nennt OAuth- und LDAP-Beispiele dagegen auch für Community; prüfen Sie das vor einer Planung. Beim ersten Login fragt die Oberfläche nach anonymer Nutzungsstatistik, die Sie mit „No, thanks“ ablehnen.

Eckdaten

Imagedbgate/dbgate:7.3.1 (auch 7.3.1-alpine, ohne SQLite)
Port3000/tcp (HTTP)
Volume/root/.dbgate (Dateien, Logs, .key)
Wichtige VariablenLOGIN_PASSWORD_<name>, LOGIN_PERMISSIONS_<name>, TOKEN_LIFETIME, CONNECTIONS, ENGINE_<id>, READONLY_<id>, WEB_ROOT
HealthcheckGET /health
LizenzGPL-3.0 (Community), Team Premium kostenpflichtig
Projektdbgate/dbgate, rund 7300 GitHub-Sterne, Stand 4. Oktober 2026

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

Legen Sie den Ordner /opt/dbgate an. Die Datei ist exakt die im Test verwendete: DbGate 7.3.1 (Release vom 24. September 2026) plus PostgreSQL und MariaDB als Beispiel. Vorhandene Datenbanken binden Sie stattdessen über deren Netzwerk an.

services:
  dbgate:
    image: dbgate/dbgate:7.3.1
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - dbgate-data:/root/.dbgate
    environment:
      # Schlüsselnamen werden von Compose nicht ersetzt: Login-Namen fest eintragen
      LOGIN_PASSWORD_admin: ${DBGATE_ADMIN_PASSWORD}
      LOGIN_PASSWORD_support: ${DBGATE_SUPPORT_PASSWORD}
      LOGIN_PERMISSIONS_support: "~connections/*, connections/pg, ~dbops/dropdb, ~dbops/sql-dump/import"
      TOKEN_LIFETIME: 8h
      LANGUAGE: de
      CONNECTIONS: pg,maria
      LABEL_pg: PostgreSQL Warenwirtschaft
      SERVER_pg: postgres
      PORT_pg: 5432
      USER_pg: ${PG_USER}
      PASSWORD_pg: ${PG_PASSWORD}
      DATABASE_pg: ${PG_DB}
      ENGINE_pg: postgres@dbgate-plugin-postgres
      LABEL_maria: MariaDB Webshop
      SERVER_maria: mariadb
      PORT_maria: 3306
      USER_maria: ${MARIA_USER}
      PASSWORD_maria: ${MARIA_PASSWORD}
      ENGINE_maria: mariadb@dbgate-plugin-mysql
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 30s
      timeout: 5s
      start_period: 20s
      retries: 3
    depends_on:
      postgres:
        condition: service_healthy
      mariadb:
        condition: service_healthy

  postgres:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${PG_USER}
      POSTGRES_PASSWORD: ${PG_PASSWORD}
      POSTGRES_DB: ${PG_DB}
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${PG_USER} -d ${PG_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

  mariadb:
    image: mariadb:11.8
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: ${MARIA_ROOT_PASSWORD}
      MARIADB_DATABASE: shop
      MARIADB_USER: ${MARIA_USER}
      MARIADB_PASSWORD: ${MARIA_PASSWORD}
    volumes:
      - maria-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  dbgate-data:
  pg-data:
  maria-data:
# .env  (chmod 600, nicht ins Git)
DBGATE_ADMIN_PASSWORD=bitte-langes-zufallskennwort
DBGATE_SUPPORT_PASSWORD=bitte-zweites-zufallskennwort
PG_USER=app
PG_PASSWORD=bitte-aendern
PG_DB=warenwirtschaft
MARIA_USER=shop
MARIA_PASSWORD=bitte-aendern
MARIA_ROOT_PASSWORD=bitte-aendern

127.0.0.1:3000 macht DbGate nur lokal erreichbar. CONNECTIONS listet die Verbindungs-IDs, zu jeder ID gehören LABEL_, SERVER_, PORT_, USER_, PASSWORD_ und das Pflichtfeld ENGINE_. Für Redis lautet er redis@dbgate-plugin-redis, für MongoDB mongo@dbgate-plugin-mongo (plus URL_<id>). Mit READONLY_<id>: 1 öffnen Sie eine Verbindung nur lesend, PASSWORD_MODE_<id>: askPassword lässt das Datenbankkennwort bei jeder Anmeldung abfragen, statt es im Container abzulegen.

Achtung bei Login-Namen: Docker Compose ersetzt ${...} nur in Werten, nicht in Schlüsselnamen. Im Test kam LOGIN_PASSWORD_${ADMIN_USER} nicht im Container an. DbGate schaltete auf den Anbieter „Anonymous“ und gab jedem Besucher ohne Kennwort Abfragerechte auf PostgreSQL. Schreiben Sie Login-Namen deshalb fest in den Schlüssel.

Verifizieren: docker compose config --quiet meldet nichts, und docker compose config | grep LOGIN_PASSWORD zeigt beide Schlüssel LOGIN_PASSWORD_admin und LOGIN_PASSWORD_support.

Schritt 2: Stack starten und Healthcheck prüfen

cd /opt/dbgate
chmod 600 .env
docker compose up -d
docker compose ps
docker compose logs dbgate | grep -E 'version|listening'

Das Image enthält kein curl; der Healthcheck nutzt daher fetch von Node.js gegen /health, das ohne Anmeldung Status und Speicherwerte liefert. Das Startprotokoll zeigt Starting API process version 7.3.1, Using connections from ENV variables (Zugangsdaten maskiert) und DbGate API listening on port 3000.

Verifizieren: docker compose ps zeigt alle drei Dienste als healthy; im Test nach rund 30 Sekunden. curl -s 127.0.0.1:3000/health antwortet mit "status": "ok".

Schritt 3: Anmeldung erzwingen und negativ testen

Die Community Edition kennt zwei Varianten: LOGIN plus PASSWORD für ein einzelnes Konto oder beliebig viele LOGIN_PASSWORD_<name>. Prüfen Sie, welcher Anbieter aktiv ist:

curl -s -X POST 127.0.0.1:3000/auth/get-providers \
  -H 'Content-Type: application/json' -d '{}'
# erwartet: {"providers":[{"amoid":"logins",...,"name":"Login & Password"}],"default":"logins"}
# Gefahr:   {"providers":[{"amoid":"none","workflowType":"anonymous",...}]}

Im Test lehnte DbGate ein leeres Kennwort, ein falsches Kennwort und einen unbekannten Benutzer jeweils mit {"error":"Invalid credentials"} ab. API-Aufrufe ohne Token beantwortete der Server mit HTTP 401 missing authorization header, ein erfundenes Token mit HTTP 401 invalid token. TOKEN_LIFETIME: 8h verkürzt die Sitzung vom Standard (ein Tag) auf einen Arbeitstag. Einen Brute-Force-Schutz hat DbGate nicht; den liefern Proxy oder VPN.

Anmeldeseite von DbGate mit der Fehlermeldung Invalid credentials nach falschem Kennwort
Falsches Kennwort: DbGate meldet „Invalid credentials“ und lässt keinen Zugriff zu.

Verifizieren: get-providers liefert logins, ein Login mit falschem Kennwort scheitert, die Anmeldung mit dem Kennwort aus der .env öffnet die Oberfläche mit beiden Verbindungen.

Schritt 4: Verbindung öffnen und erste Abfrage ausführen

Als admin sehen Sie links beide Verbindungen. Ein Klick verbindet, ein Klick auf eine Tabelle öffnet die Datenansicht. Über das Plus oben rechts und „Abfrage“ öffnen Sie den SQL-Editor.

DbGate-Oberfläche mit den Verbindungen MariaDB Webshop und PostgreSQL Warenwirtschaft und geöffneter Tabelle artikel
Datenansicht der Tabelle „artikel“ in der vorkonfigurierten PostgreSQL-Verbindung.
SQL-Editor in DbGate mit einer Abfrage auf Artikel unter Mindestbestand und einer Ergebniszeile
SQL-Editor mit Abfrage auf Artikel unter Mindestbestand und Ergebnis.

Verifizieren: Die Statusleiste unten zeigt „Connected“ und die Serverversion (im Test PostgreSQL 17.11 und MariaDB 11.8.9). Eine Abfrage wie SELECT version(); liefert eine Ergebniszeile.

Schritt 5: Zweites Konto mit eingeschränkten Rechten

Für Support oder Dienstleister vergeben Sie mit LOGIN_PERMISSIONS_<name> eine Rechteliste. Ein vorangestelltes ~ entzieht ein Recht. Die Zeile aus Schritt 1 entzieht dem Konto support alle Verbindungen außer pg und verbietet DROP DATABASE sowie den Import von SQL-Dumps.

DbGate angemeldet als Benutzer support, in der Verbindungsliste steht nur PostgreSQL Warenwirtschaft
Das Konto „support“ sieht nur die freigegebene PostgreSQL-Verbindung.

Diese Rechte gelten in DbGate, nicht in der Datenbank: Per SQL bleibt DELETE möglich. Für reine Lesezugriffe nutzen Sie einen Datenbankbenutzer nur mit SELECT plus READONLY_<id>: 1.

Verifizieren: Als support erscheint nur „PostgreSQL Warenwirtschaft“. Ein direkter API-Aufruf auf die MariaDB-Verbindung scheiterte im Test mit DBGM-00264 Connection permission not granted.

Schritt 6: Reverse Proxy mit TLS

DbGate spricht selbst nur HTTP. Veröffentlichen Sie es über Ihren vorhandenen Proxy, zum Beispiel Nginx, Caddy oder Traefik (siehe Reverse Proxy im Vergleich). Wichtig ist der Pfad /stream: Darüber schiebt der Server Statusmeldungen als dauerhaften Datenstrom an den Browser. Im Test hinter einem HTTPS-Proxy hing die Strukturansicht einmal bei „Lade Datenbankstruktur“ bis zum Neuladen; schalten Sie die Pufferung ab. Für einen Unterpfad wie /dbadmin setzen Sie WEB_ROOT.

server {
    listen 443 ssl;
    http2 on;
    server_name db.example.de;
    # ssl_certificate / ssl_certificate_key wie bei Ihren übrigen Diensten

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # /stream ist ein dauerhafter Ereignisstrom: nicht puffern
        proxy_buffering off;
        proxy_read_timeout 1h;
        client_max_body_size 200m;
    }
}

Ergänzen Sie eine IP-Freigabe (allow/deny) oder nutzen Sie nur ein VPN. Die Datenbanken haben keine ports:-Zeile und bleiben im Compose-Netz.

Verifizieren: curl -I https://db.example.de/ liefert HTTP 200, der Browser leitet auf /login.html weiter, und ss -tlnp | grep 3000 zeigt nur 127.0.0.1:3000.

Schritt 7: Backup und Restore der DbGate-Daten

Das Volume /root/.dbgate enthält gespeicherte SQL-Skripte, Diagramme und Archive unter files/, Protokolle unter logs/ und die Datei .key. Mit ihr verschlüsselt DbGate laut Quellcode Kennwörter von Verbindungen, die in der Oberfläche gespeichert werden; ohne sie sind diese nach einem Restore unbrauchbar. Datenbanken sichern Sie getrennt mit pg_dump bzw. mariadb-dump. Den Volume-Namen (hier dbgate_dbgate-data) zeigt docker volume ls.

docker compose stop dbgate
docker run --rm -v dbgate_dbgate-data:/data:ro -v "$PWD/backup":/backup \
  alpine tar czf /backup/dbgate-data-$(date +%F).tar.gz -C /data .
docker compose start dbgate

Wiederherstellen in ein leeres oder beschädigtes Volume:

docker compose stop dbgate
docker run --rm -v dbgate_dbgate-data:/data -v "$PWD/backup":/backup alpine \
  sh -c 'rm -rf /data/* /data/.[!.]* ; tar xzf /backup/dbgate-data-2026-10-04.tar.gz -C /data'
docker compose start dbgate

Im Test lag eine gespeicherte Abfrage mit der Markierung MARKER-DBGATE-2026 im Volume. Sie überstand ein --force-recreate, war nach dem Löschen des Volumes verschwunden (Dateiliste leer) und nach dem Restore wieder da, inklusive Inhalt.

Verifizieren: tar tzf backup/dbgate-data-*.tar.gz listet ./.key und ./files/; nach dem Restore erscheinen Ihre gespeicherten Abfragen wieder in der Dateiliste der Oberfläche.

Schritt 8: Updates und Rollback

Schreiben Sie die Version fest statt latest. Vor einem Update sichern Sie das Volume und ändern den Tag:

docker compose pull dbgate
docker compose up -d dbgate
docker compose logs dbgate | grep 'Starting API process version'

Im Test lief ein Wechsel von 7.3.1 auf 7.3.0 und zurück ohne Datenverlust; die gespeicherte Abfrage blieb erhalten. Nach jedem Neustart müssen sich alle Benutzer neu anmelden: Das Signaturgeheimnis der Sitzungstoken wird pro Prozess neu erzeugt, alte Token werden mit HTTP 401 invalid token abgewiesen, im Protokoll steht JsonWebTokenError: invalid signature.

Verifizieren: Das Startprotokoll nennt die neue Version, docker compose ps zeigt healthy, die Anmeldung funktioniert.

Troubleshooting

FehlerbildUrsacheLösung
Keine Anmeldeseite, Oberfläche öffnet sofortKeine gültige Variable LOGIN_PASSWORD_* bzw. LOGIN/PASSWORD im ContainerSchlüsselnamen fest schreiben, mit docker compose exec dbgate env prüfen
connect ECONNREFUSED 127.0.0.1:5432localhost als Server: Im Container ist das DbGate selbstDienstnamen eintragen (postgres, mariadb)
Invalid credentialsFalsches Kennwort oder Tippfehler im Login-NamenWerte in .env und Schlüssel prüfen, dann docker compose up -d
DBGM-00264 Connection permission not grantedKonto hat die Verbindung nicht in LOGIN_PERMISSIONS_*connections/<id> ergänzen
Nach Neustart abgemeldet, invalid signature im LogNeues Token-Geheimnis je ProzessNormal, neu anmelden
„Lade Datenbankstruktur“ bleibt stehenProxy puffert /streamproxy_buffering off, Seite neu laden

Den Host-Fehler können Sie im Container nachvollziehen: docker compose exec dbgate getent hosts postgres liefert die interne IP, eine Verbindung auf localhost:5432 scheitert dagegen mit ECONNREFUSED. Für eine Datenbank direkt auf dem Docker-Host trägt das Startskript des Images den Namen dockerhost (Standard-Gateway) ein.

DbGate entfernen

Warnung: docker compose down -v löscht alle Volumes dieses Projekts, im Beispiel also auch die PostgreSQL- und MariaDB-Daten. Sichern Sie vorher Datenbanken und DbGate-Volume. Nur DbGate entfernen Sie mit docker compose rm -sf dbgate und docker volume rm dbgate_dbgate-data; Ihre Datenbanken bleiben dabei unberührt.

Häufige Fragen

Kann ich Verbindungen in der Oberfläche anlegen statt per Umgebungsvariable?

Ja, wenn Sie CONNECTIONS weglassen. Sie liegen dann verschlüsselt im Volume und gelten für alle Konten.

Unterstützt die Community Edition Benutzerrollen?

Nur über LOGIN_PERMISSIONS_* je Konto. Rollen, Administrationsoberfläche und eine Speicherdatenbank für Einstellungen gibt es laut Hersteller in Team Premium.

Darf DbGate eigene Skripte ausführen?

JavaScript-Shell-Skripte (SHELL_SCRIPTING) und Verbindungen in Skripten (SHELL_CONNECTION) sind standardmäßig aus. Lassen Sie das so, wenn Dritte Zugang haben.

Fazit

DbGate ist schnell aufgesetzt, sparsam und gut versionierbar. Die gefährlichste Falle: Ohne gültige Login-Variable startet die Oberfläche offen. Prüfen Sie den aktiven Anbieter nach jeder Änderung, binden Sie den Port lokal, setzen Sie Proxy mit TLS oder VPN davor und vergeben Sie minimale Datenbankrechte. Für Rollen und Single Sign-on lohnt der Blick auf Team Premium.

Weiterführende Anleitungen und Quellen

DbGateDocker ComposePostgreSQLMariaDBDatenbank-ManagerSelfhostingReverse Proxy