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

CloudBeaver mit Docker Compose: Datenbank-Manager im Browser

CloudBeaver Community Edition bringt SQL-Editor und Datenbankverwaltung in den Browser. Diese Anleitung zeigt die Installation mit Docker Compose samt PostgreSQL-Testdatenbank, erklärt alle wichtigen Umgebungsvariablen, sichert den Workspace ab und beschreibt Backup, Wiederherstellung und Update. Alle Befehle und Ausgaben stammen aus einem echten Testlauf.

Illustration zur Verwaltung von Datenbanken im Browser mit einem containerisierten Datenbank-Manager und einem Konfigurationsbeispiel im Vordergrund KI-generiert

Wer mehrere Datenbanken betreut, kennt das Problem: Auf jedem Admin-Rechner liegt eine eigene Installation eines Datenbank-Werkzeugs, mit eigenen gespeicherten Zugangsdaten und eigenem Konfigurationsstand. CloudBeaver Community Edition dreht das um. Der Datenbank-Manager läuft als Container auf einem Server, die Bedienung erfolgt im Browser, und Verbindungen sowie Berechtigungen werden zentral verwaltet.

Diese Anleitung zeigt eine vollständige Installation mit Docker Compose, zusammen mit einer PostgreSQL-Testdatenbank. Alle Befehle und Ausgaben in dieser Anleitung stammen aus einem echten Testlauf auf einem Linux-Host mit Docker 29.1.3 und Docker Compose 2.40.3 am 19. September 2026. Wo etwas nicht selbst ausgeführt wurde, steht das ausdrücklich dabei.

Wofür CloudBeaver taugt und wo die Grenzen liegen

CloudBeaver ist ein webbasierter Datenbank-Manager des DBeaver-Projekts. Die Community Edition steht unter der Apache-2.0-Lizenz und lässt sich ohne Lizenzschlüssel betreiben. Im Browser bekommt das Team einen SQL-Editor, einen Daten-Editor mit Tabellenansicht, einen Navigator über Schemata und Objekte sowie Import- und Exportfunktionen.

Der typische Nutzen im KMU-Umfeld: Ein Entwickler, ein externer Dienstleister oder ein Fachanwender braucht lesenden Zugriff auf eine Datenbank, soll aber weder einen VPN-Zugang zum Datenbankserver noch die Zugangsdaten im Klartext erhalten. CloudBeaver sitzt dazwischen, hält die Verbindungsdaten zentral und vergibt Benutzerkonten mit Rollen.

Genauso wichtig sind die Grenzen:

  • Kein Ersatz für DBeaver Desktop. Die Desktop-Anwendung hat deutlich mehr Funktionen, etwa umfangreichere Werkzeuge zur Schema-Bearbeitung und Diagramme. Die Weboberfläche deckt den Alltag ab, nicht jeden Sonderfall.
  • Kein Datenbank-Monitoring. CloudBeaver zeigt keine Metriken über Zeit, keine Alarme, keine Auslastungsgrafiken. Wer Antwortzeiten, Sperren oder Replikationsverzug überwachen will, braucht zusätzlich ein Monitoring-System.
  • Community Edition gegenüber Enterprise. Laut offizieller Dokumentation bleiben Funktionen wie erweiterte Benutzerverwaltung über externe Identitätsanbieter, Cluster-Betrieb und kommerzieller Support der kostenpflichtigen Enterprise Edition vorbehalten. Die Community Edition bringt lokale Benutzerverwaltung mit.
  • Kein Backup-Werkzeug. CloudBeaver sichert keine Datenbanken. Datenbank-Backups bleiben Aufgabe der jeweiligen Datenbank.
  • Eingebettete Konfigurationsdatenbank. In der Standardkonfiguration speichert CloudBeaver seine eigenen Einstellungen in einer eingebetteten H2-Datenbank im Workspace. Das ist im Testlauf bestätigt worden und für kleine Installationen völlig ausreichend, skaliert aber nicht auf viele parallele Instanzen.

Geprüftes Projekt und Versionsstand

Alle folgenden Angaben wurden am 19. September 2026 selbst abgerufen und nicht aus Sekundärquellen übernommen.

AngabeWertQuelle, Stand 19. September 2026
Repositorydbeaver/cloudbeaverGitHub-API
Sterne5150GitHub-API
Letzter Push18. September 2026GitHub-API
LizenzApache-2.0GitHub-API
ArchiviertneinGitHub-API
Aktuelle Version26.2.0 vom 31. August 2026Docker-Hub-Tag-Liste und README-Changelog
Architekturenamd64 und arm64Docker-Hub-Tag-Liste
Image-Größe1,16 GB entpackteigener Testlauf, docker images

Der laufende Container hat sich im Testlauf selbst mit dem Build 26.2.0.202608310912 gemeldet, sowohl im Startprotokoll als auch über die API. Die Versionsangabe stammt also nicht nur vom Image-Tag, sondern aus der laufenden Anwendung.

Dass beide Architekturen angeboten werden, ist für die Praxis relevant: Die Anleitung funktioniert auf einem gewöhnlichen x86-Server ebenso wie auf ARM-Hardware, etwa einem Raspberry Pi 5 mit ausreichend Arbeitsspeicher. Der eigene Testlauf fand ausschließlich auf amd64 statt, die arm64-Unterstützung ist anhand der Tag-Liste belegt, aber nicht selbst ausprobiert.

Voraussetzungen und Ressourcenbedarf

CloudBeaver ist eine Java-Anwendung und läuft im Container mit einem Jetty-Webserver. Im Testlauf meldete der Container Jetty 12.1.11 auf einer Java-Laufzeit 25.0.4 von Eclipse Adoptium.

  • Docker und Docker Compose. Getestet mit Docker 29.1.3 und Compose 2.40.3. Ältere Versionen ab Compose v2 sollten ebenfalls funktionieren, das wurde nicht geprüft.
  • Arbeitsspeicher. Im Leerlauf belegte der CloudBeaver-Container im Testlauf rund 262 MB, die PostgreSQL-Testdatenbank rund 28 MB. Eine JVM belegt unter Last deutlich mehr. Planen Sie für den produktiven Betrieb mindestens 1 GB für CloudBeaver allein ein, bei großen Ergebnismengen mehr.
  • Plattenplatz. Das Image belegt entpackt 1,16 GB. Dazu kommen der Workspace mit Konfiguration und die heruntergeladenen JDBC-Treiber. Rechnen Sie mit etwa 3 GB, damit Updates Platz haben.
  • Startzeit. Der erste Start bis zur Antwort der Weboberfläche dauerte im Testlauf rund 39 Sekunden, ein Neustart des bereits eingerichteten Containers rund 27 Sekunden. Eine JVM startet nicht sofort, das ist normal und kein Fehler.
  • Netz. Für das Nachladen von JDBC-Treibern braucht der Container beim ersten Verbindungsaufbau in der Regel Internetzugang, sofern der Treiber nicht bereits im Image enthalten ist.

Verzeichnisstruktur und persistente Pfade

Der gesamte veränderliche Zustand von CloudBeaver liegt unter einem einzigen Pfad im Container: /opt/cloudbeaver/workspace. Wird dieser Pfad nicht persistent abgelegt, sind nach jedem Neuaufsetzen des Containers alle Benutzer, Verbindungen und Einstellungen verloren.

Im Testlauf zeigte der frisch gestartete Workspace folgende Struktur, ausgelesen direkt aus dem laufenden Container:

# Inhalt des Workspace nach dem ersten Start
drwxrwxr-x  dbeaver dbeaver  .data
drwxrwxr-x  dbeaver dbeaver  GlobalConfiguration
drwxrwxr-x  dbeaver dbeaver  .metadata

# In .data liegt die eingebettete Konfigurationsdatenbank
-rw-rw-r--  dbeaver dbeaver  cb.h2v2.dat.mv.db
-rw-rw-r--  dbeaver dbeaver  cb.h2v2.dat.trace.db
-rw-rw-r--  dbeaver dbeaver  .database-credentials.dat

# Die angelegten Verbindungen landen hier
GlobalConfiguration/.dbeaver/data-sources.json

Zu den Dateirechten ein wichtiger Punkt aus dem Testlauf: Die Dateien im Workspace gehören dem Benutzer dbeaver, der Hauptprozess im Container lief jedoch als root. Wer statt eines benannten Docker-Volumes ein Bind-Mount auf ein Hostverzeichnis verwendet, muss dem Verzeichnis passende Rechte geben, sonst startet der Server nicht sauber. Ein benanntes Volume, wie in dieser Anleitung verwendet, umgeht das Problem, weil Docker die Rechte beim ersten Befüllen vom Image übernimmt. Für Einsteiger ist das benannte Volume die verlässlichere Wahl.

Die mitgelieferte Serverkonfiguration liegt unter /opt/cloudbeaver/conf/cloudbeaver.conf und ist im Image bereits so aufgebaut, dass sie Werte aus Umgebungsvariablen zieht. Deshalb lässt sich fast alles über Compose steuern, ohne eine eigene Konfigurationsdatei einzuhängen.

Die vollständige compose.yaml

Diese Datei wurde im Testlauf genau so gestartet. Sie legt zwei Dienste an: CloudBeaver selbst und eine PostgreSQL-Datenbank, an der sich der Verbindungsaufbau ausprobieren lässt. Wer bereits eine Datenbank betreibt, lässt den zweiten Dienst weg.

services:
  cloudbeaver:
    image: dbeaver/cloudbeaver:26.2.0
    container_name: cloudbeaver
    restart: unless-stopped
    ports:
      # Nur an localhost binden, Veroeffentlichung uebernimmt der Reverse Proxy
      - "127.0.0.1:8978:8978"
    volumes:
      - cloudbeaver_workspace:/opt/cloudbeaver/workspace
    environment:
      TZ: Europe/Berlin
      CLOUDBEAVER_WEB_SERVER_PORT: "8978"
      # Anonymen Zugriff ausdruecklich abschalten
      CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED: "false"
      # Eigene Verbindungen durch Benutzer erlauben
      CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS: "true"
      # Oberflaeche auf Deutsch vorbelegen
      CLOUDBEAVER_CORE_LOCALIZATION: "de"
      # Schutz gegen Passwortraten aktiv lassen
      CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED: "true"
      CLOUDBEAVER_MAX_FAILED_LOGINS: "10"
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - cb_net

  postgres:
    image: postgres:17-alpine
    container_name: cloudbeaver-postgres
    restart: unless-stopped
    ports:
      # Nur fuer lokale Werkzeuge, nicht nach aussen oeffnen
      - "127.0.0.1:5432:5432"
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - cb_net

volumes:
  cloudbeaver_workspace:
  postgres_data:

networks:
  cb_net:
    driver: bridge

Die wichtigsten Entscheidungen in dieser Datei:

  • Feste Versionsangabe statt latest. Mit 26.2.0 weiß jeder im Team, welcher Stand läuft. Ein latest kann bei einem beliebigen Neustart stillschweigend auf eine neue Hauptversion springen, was bei CloudBeaver wegen der Workspace-Migration besonders unangenehm ist.
  • Bindung an 127.0.0.1. Ohne diesen Präfix veröffentlicht Docker den Port auf allen Schnittstellen und umgeht dabei üblicherweise die Host-Firewall. Das ist der häufigste Weg, wie ein Datenbank-Manager versehentlich im Internet landet.
  • Der Healthcheck an PostgreSQL mit depends_on. CloudBeaver startet erst, wenn die Datenbank wirklich Verbindungen annimmt, nicht schon wenn der Container existiert. Im Testlauf war das im Startprotokoll klar nachvollziehbar.
  • Ein eigenes Netzwerk. Beide Dienste finden sich über ihre Servicenamen, ohne dass Ports auf dem Host geöffnet werden müssen.

Die .env-Datei

Die Zugangsdaten der Datenbank gehören nicht in die Compose-Datei, sondern in eine .env im selben Verzeichnis. Diese Datei darf niemals in ein Git-Repository gelangen.

# .env, liegt neben der compose.yaml
# Diese Werte sind Platzhalter und muessen ersetzt werden
POSTGRES_DB=demo_db
POSTGRES_USER=demo_user
POSTGRES_PASSWORD=HIER_EIN_LANGES_ZUFALLSPASSWORT_EINSETZEN

Ein brauchbares Passwort erzeugen Sie so, und zwar für jede Installation neu:

# Zufallspasswort erzeugen und direkt anzeigen
openssl rand -base64 32

# Rechte der .env einschraenken, damit nur der Besitzer sie lesen kann
chmod 600 .env

# Pruefen, dass Compose die Werte korrekt einsetzt
docker compose config | grep -A2 POSTGRES_USER

Der Befehl docker compose config löst alle Variablen auf und zeigt die Datei so, wie Docker sie tatsächlich sieht. Das ist die schnellste Methode, um Tippfehler in Variablennamen zu finden, bevor ein Container startet.

Die wichtigsten Umgebungsvariablen

Die folgenden Variablennamen wurden im Testlauf direkt aus der Datei cloudbeaver.conf im laufenden Image ausgelesen, sind also nicht aus der Dokumentation abgeschrieben. Die angegebenen Standardwerte sind die Vorgaben des Images in Version 26.2.0.

VariableStandardBedeutung
CLOUDBEAVER_WEB_SERVER_PORT8978Port, auf dem Jetty im Container lauscht
CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLEDtrueZugriff ohne Anmeldung. Sollte auf false stehen
CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONSfalseDürfen Benutzer selbst Verbindungen anlegen
CLOUDBEAVER_CORE_LOCALIZATIONenSprache der Oberfläche, de wird unterstützt
CLOUDBEAVER_FORCE_HTTPSfalseErzwingt HTTPS. Hinter einem Reverse Proxy meist nicht nötig
CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLEDtrueSperrt nach zu vielen Fehlversuchen
CLOUDBEAVER_MAX_FAILED_LOGINS10Fehlversuche bis zur Sperre
CLOUDBEAVER_BLOCK_PERIOD300Sperrdauer in Sekunden
CLOUDBEAVER_POLICY_MIN_LENGTH8Mindestlänge für Benutzerpasswörter
CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD1800000Sitzungsablauf in Millisekunden, entspricht 30 Minuten
CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT100000Obergrenze für Zeilen je Ergebnis, schützt den Arbeitsspeicher
CLOUDBEAVER_DB_BACKUP_ENABLEDtrueSicherung der internen H2-Datenbank vor Schema-Migrationen
CLOUDBEAVER_APP_FORWARD_PROXYfalseAuswertung von Proxy-Kopfzeilen, relevant hinter einem Reverse Proxy

Die Standardwerte anonymousAccessEnabled: true und CLOUDBEAVER_POLICY_MIN_LENGTH: 8 verdienen besondere Aufmerksamkeit. Beides sollte vor dem Produktivbetrieb angepasst werden, der anonyme Zugriff zwingend.

Start und Ersteinrichtung

Legen Sie ein Verzeichnis an, speichern Sie dort die beiden Dateien und starten Sie den Stapel:

# Arbeitsverzeichnis anlegen
mkdir -p /opt/stacks/cloudbeaver
cd /opt/stacks/cloudbeaver

# compose.yaml und .env in diesem Verzeichnis ablegen, dann starten
docker compose up -d

# Status der Dienste pruefen
docker compose ps

# Startprotokoll von CloudBeaver mitlesen
docker compose logs -f cloudbeaver

Im Testlauf sah die Statusausgabe nach dem Start so aus, hier leicht gekürzt:

NAME                   IMAGE                        SERVICE       STATUS
cloudbeaver            dbeaver/cloudbeaver:26.2.0   cloudbeaver   Up 42 seconds
cloudbeaver-postgres   postgres:17-alpine           postgres      Up 53 seconds (healthy)

Im Protokoll erscheint beim ersten Start dieser Hinweis, der genau richtig ist und keinen Fehler darstellt:

INFO  io.cloudbeaver.server.CBApplication - No auto configuration was found. Server must be configured manually
DEBUG io.cloudbeaver.server.CBApplication - CloudBeaver Community 26.2.0.202608310912 is starting
INFO  org.eclipse.jetty.server.AbstractConnector - Started ServerConnector{HTTP/1.1}{0.0.0.0:8978}

Danach rufen Sie die Oberfläche unter http://127.0.0.1:8978/ auf. Beim ersten Aufruf befindet sich der Server im Konfigurationsmodus. Im Testlauf war das über die API eindeutig nachweisbar: Die Abfrage der Serverkonfiguration meldete configurationMode: true und einen noch leeren Servernamen. In diesem Modus führt die Oberfläche durch die Ersteinrichtung, bei der Servername, Server-URL und vor allem das erste Administratorkonto festgelegt werden.

Ehrlichkeitshalber: Das Ausfüllen dieses Einrichtungsassistenten erfolgt im Browser und wurde in diesem Testlauf nicht selbst durchgeklickt, da er nur über die grafische Oberfläche bedienbar ist. Nachgewiesen wurden der Konfigurationsmodus selbst, die Erreichbarkeit der Oberfläche und die Tatsache, dass der Server ohne Ersteinrichtung keine privaten Projekte freigibt. Ein API-Aufruf zum Anlegen einer Verbindung scheiterte im nicht eingerichteten Zustand erwartungsgemäß mit Access to private project is denied.

Wählen Sie beim Anlegen des Administratorkontos ein langes, einmaliges Passwort. Dieses Konto darf sämtliche hinterlegten Datenbankverbindungen nutzen und ist damit so schützenswert wie ein Datenbank-Superuser.

Verbindung zur PostgreSQL-Datenbank anlegen

Nach der Ersteinrichtung legen Sie in der Oberfläche unter den Verbindungen eine neue PostgreSQL-Verbindung an. Entscheidend ist dabei ein Punkt, an dem erfahrungsgemäß die meisten Installationen hängen bleiben: Als Host gehört der Servicename aus der Compose-Datei eingetragen, also postgres, nicht localhost.

Der Grund: localhost bezeichnet aus Sicht des CloudBeaver-Containers diesen Container selbst, und dort läuft keine Datenbank. Das ließ sich im Testlauf sauber in beide Richtungen belegen. Aus dem CloudBeaver-Container heraus war die Datenbank über den Servicenamen erreichbar, über localhost dagegen nicht:

# Namensaufloesung im Compose-Netz
getent hosts postgres
172.20.0.2      postgres

# Verbindungstest auf den Servicenamen, erfolgreich
TCP postgres:5432 OK

# Gegenprobe auf localhost, schlaegt erwartungsgemaess fehl
localhost:5432 NICHT erreichbar

Die Verbindungsparameter lauten entsprechend:

FeldWert
TreiberPostgreSQL
Hostpostgres
Port5432
DatenbankWert aus POSTGRES_DB
BenutzerWert aus POSTGRES_USER
PasswortWert aus POSTGRES_PASSWORD

Zum Ausprobieren legen Sie sich eine kleine Testtabelle an. Im Testlauf wurde genau das gemacht, damit in der Oberfläche auch etwas zu sehen ist:

# Testtabelle anlegen und befuellen
docker compose exec postgres psql -U demo_user -d demo_db -c   "CREATE TABLE kunden (id serial primary key, name text, ort text);"

docker compose exec postgres psql -U demo_user -d demo_db -c   "INSERT INTO kunden (name, ort) VALUES ('Beispiel GmbH','Dresden');"

# Inhalt kontrollieren
docker compose exec postgres psql -U demo_user -d demo_db -c "SELECT * FROM kunden;"

Ein Hinweis zu den Treibern: Die Serverkonfiguration deaktiviert im Auslieferungszustand mehrere dateibasierte Treiber, im Testlauf abgefragt waren das DuckDB, die eingebetteten H2-Varianten und SQLite. Das ist eine bewusste Schutzmaßnahme, weil solche Treiber Dateizugriffe auf dem Server ermöglichen würden.

Funktions- und Healthcheck

CloudBeaver bringt im Image keinen eigenen Healthcheck mit. Es lohnt sich, einen zu ergänzen, damit Docker einen hängenden Container selbst erkennt. Das Image stellt dafür einen Statuspfad bereit, der im Testlauf mit HTTP 200 geantwortet hat:

    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://localhost:8978/status || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 90s

Die großzügige start_period ist wichtig. Eine JVM braucht Zeit, und im Testlauf antwortete die Oberfläche erst nach rund 39 Sekunden. Ein zu kurz gewähltes Zeitfenster lässt Compose den Container fälschlich als ungesund markieren und gegebenenfalls in einer Neustartschleife kreisen.

Von Hand prüfen Sie die Erreichbarkeit so:

# Antwortet die Oberflaeche?
curl -s -o /dev/null -w "%{http_code}
" http://127.0.0.1:8978/

# Statuspfad des Servers
curl -s -o /dev/null -w "%{http_code}
" http://127.0.0.1:8978/status

# Laufende Version direkt aus der Anwendung auslesen
docker compose logs cloudbeaver | grep "is starting"

Der letzte Befehl ist der verlässlichste Weg zur Versionsprüfung, weil er die tatsächlich laufende Fassung zeigt und nicht nur den Namen des Images.

Sichere Netzwerkfreigabe und Reverse Proxy mit TLS

Stellen Sie CloudBeaver niemals ungeschützt ins Internet. Das ist keine Formalie. Die Anwendung hält Zugangsdaten zu Ihren Datenbanken vor und bietet einen SQL-Editor, der Daten lesen und ändern kann. Wer die Oberfläche erreicht und ein Passwort errät, hat Zugriff auf die dahinterliegenden Daten. Erschwerend kommt hinzu, dass der anonyme Zugriff im Auslieferungszustand aktiviert ist.

Beachten Sie daher folgende Reihenfolge:

  • Den Port ausschließlich an 127.0.0.1 binden, wie in der Compose-Datei oben.
  • CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED auf false setzen, bevor der Dienst erreichbar wird.
  • Die Ersteinrichtung mit dem Administratorkonto sofort abschließen, nicht später.
  • Erst danach einen Reverse Proxy mit TLS davorsetzen.
  • Wenn es der Anwendungsfall zulässt, zusätzlich auf VPN oder eine Zugriffsbeschränkung nach Quell-IP setzen.

Mit Caddy ist die Konfiguration kurz, weil das Zertifikat automatisch bezogen wird:

datenbank.example.com {
    reverse_proxy 127.0.0.1:8978

    # Zugriff auf bekannte Netze begrenzen, optional aber empfohlen
    @erlaubt remote_ip 203.0.113.0/24 198.51.100.10
    handle @erlaubt {
        reverse_proxy 127.0.0.1:8978
    }
}

Mit nginx sieht der passende Serverblock so aus. Die Kopfzeilen für WebSockets sind nötig, weil die Oberfläche Ereignisse über eine dauerhafte Verbindung bezieht:

server {
    listen 443 ssl http2;
    server_name datenbank.example.com;

    ssl_certificate     /etc/letsencrypt/live/datenbank.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/datenbank.example.com/privkey.pem;

    # Grosse Importdateien zulassen
    client_max_body_size 128M;

    location / {
        proxy_pass http://127.0.0.1:8978;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Dauerverbindung fuer Ereignisse der Oberflaeche
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Lange laufende Abfragen nicht abschneiden
        proxy_read_timeout 300s;
    }
}

Wenn Sie einen Reverse Proxy einsetzen, setzen Sie zusätzlich CLOUDBEAVER_APP_FORWARD_PROXY auf true, damit die Anwendung die weitergereichte Client-Adresse auswertet. Sonst sieht der Schutz gegen Passwortraten alle Anfragen als von derselben Adresse kommend.

Der AI Assistant und die Datenschutzfolgen

Version 26.2.0 hat laut Changelog im Projekt-README einen AI Assistant eingeführt. Dazu gehören ein Chat im SQL-Editor, der Abfragen erzeugt und korrigiert, sowie die Möglichkeit, mehrere KI-Profile mit Tokens, Engines und Modellen für OpenAI und Copilot in der Administration zu hinterlegen. Das Vorhandensein der Funktion ließ sich im Testlauf im Container bestätigen, dort sind entsprechende Erweiterungen geladen.

Für Unternehmen mit personenbezogenen Daten ist das eine Entscheidung mit Gewicht. Damit der Assistent eine sinnvolle Abfrage erzeugen kann, braucht er Kontext, und dieser Kontext besteht aus Ihren Tabellen- und Spaltennamen, gegebenenfalls aus Beispieldaten. Wird ein externer Anbieter genutzt, verlassen diese Informationen Ihre Infrastruktur und gehen an einen Dritten. Schon Schemainformationen können aufschlussreich sein, wenn Tabellen etwa patienten oder gehaltsabrechnung heißen.

Das Projekt weist im Changelog ausdrücklich darauf hin, dass sämtliche KI-Funktionen in der Serverkonfiguration abgeschaltet werden können. Wer in einem regulierten Umfeld arbeitet oder keine Auftragsverarbeitung mit dem jeweiligen KI-Anbieter geschlossen hat, sollte genau das tun und die Abschaltung dokumentieren. Die Funktion ist ohne hinterlegten API-Schlüssel ohnehin nicht nutzbar, sie läuft also nicht unbemerkt an. Eine bewusste Entscheidung samt Vermerk ist trotzdem der sauberere Weg, weil ein Administrator den Schlüssel sonst jederzeit nachtragen kann.

Backup und vollständige Wiederherstellung

Zu sichern sind zwei Dinge: der CloudBeaver-Workspace mit Benutzern und Verbindungen, sowie die Nutzdaten der Datenbanken selbst. Für Letzteres verwenden Sie die Bordmittel der jeweiligen Datenbank, bei PostgreSQL also pg_dump.

Das folgende Verfahren für den Workspace wurde im Testlauf vollständig durchgespielt, einschließlich eines absichtlich herbeigeführten Datenverlusts und der anschließenden Wiederherstellung.

# 1. Container stoppen, damit die H2-Datenbank nicht mitten im Schreiben gesichert wird
docker compose stop cloudbeaver

# 2. Volume in ein Archiv sichern
docker run --rm   -v cloudbeaver_cloudbeaver_workspace:/workspace:ro   -v /opt/backups/cloudbeaver:/backup   alpine tar czf /backup/cloudbeaver-workspace.tar.gz -C /workspace .

# 3. Datenbank getrennt sichern
docker compose exec -T postgres pg_dump -U demo_user demo_db   > /opt/backups/cloudbeaver/demo_db.sql

# 4. Container wieder starten
docker compose start cloudbeaver

Den genauen Volumenamen ermitteln Sie vorher, da Compose den Verzeichnisnamen als Präfix voranstellt:

docker volume ls --filter name=cloudbeaver

Die Wiederherstellung läuft in umgekehrter Richtung. Im Testlauf wurde dafür der Workspace vollständig geleert, sodass das Archiv wirklich die einzige verbliebene Quelle war:

# 1. Container stoppen
docker compose stop cloudbeaver

# 2. Archiv in das Volume zurueckspielen
docker run --rm   -v cloudbeaver_cloudbeaver_workspace:/workspace   -v /opt/backups/cloudbeaver:/backup:ro   alpine tar xzf /backup/cloudbeaver-workspace.tar.gz -C /workspace

# 3. Container starten
docker compose start cloudbeaver

# 4. Erreichbarkeit pruefen
curl -s -o /dev/null -w "%{http_code}
" http://127.0.0.1:8978/

Das Ergebnis des Testlaufs: Nach dem Leeren des Volumes enthielt der Workspace null Dateien. Nach dem Entpacken des Archivs waren sowohl eine zuvor abgelegte Markierungsdatei als auch die H2-Konfigurationsdatenbank wieder vorhanden, und die Oberfläche antwortete nach rund 24 Sekunden wieder mit HTTP 200. Das Verfahren ist damit nicht nur beschrieben, sondern nachweislich funktionsfähig.

Ein Backup, das nie zurückgespielt wurde, ist kein Backup. Planen Sie diesen Durchlauf einmal bewusst auf einem Testsystem ein, bevor Sie ihn im Ernstfall zum ersten Mal brauchen.

Updates und die Grenzen des Rollbacks

Das Update selbst ist unspektakulär. Der entscheidende Schritt ist der erste:

# 1. Zuerst sichern, ohne Ausnahme
docker compose stop cloudbeaver
docker run --rm   -v cloudbeaver_cloudbeaver_workspace:/workspace:ro   -v /opt/backups/cloudbeaver:/backup   alpine tar czf /backup/workspace-vor-update.tar.gz -C /workspace .

# 2. Versionsangabe in der compose.yaml auf die neue Fassung setzen

# 3. Neues Image laden
docker compose pull cloudbeaver

# 4. Container mit dem neuen Image neu erstellen
docker compose up -d

# 5. Migration im Protokoll verfolgen
docker compose logs -f cloudbeaver

Nun zur wichtigsten Einschränkung. CloudBeaver migriert beim Start das Schema seiner internen Konfigurationsdatenbank auf den Stand der neuen Version. Diese Migration ist in der Regel nicht rückwärtskompatibel. Setzen Sie die Versionsangabe im Nachhinein wieder herunter, trifft die ältere Fassung auf ein Schema aus der Zukunft und verweigert im unglücklichsten Fall den Dienst.

Ein Rollback bedeutet deshalb praktisch immer: altes Image plus das vor dem Update angelegte Workspace-Archiv zurückspielen. Alle Änderungen, die nach dem Update in CloudBeaver vorgenommen wurden, gehen dabei verloren. Das Image bringt für diesen Fall eine eigene Sicherung mit, gesteuert über CLOUDBEAVER_DB_BACKUP_ENABLED, die standardmäßig aktiv ist und vor Schema-Änderungen greift. Verlassen Sie sich trotzdem nicht darauf, sondern machen Sie Ihre eigene Sicherung. Überspringen Sie außerdem keine Hauptversionen, sondern aktualisieren Sie schrittweise.

Typische Fehler, Diagnose und Lösung

Port bereits belegt. Startet der Container nicht, meldet Docker das unmissverständlich. Diese Ausgabe stammt aus dem Testlauf, in dem der Konflikt absichtlich herbeigeführt wurde:

docker: Error response from daemon: failed to set up container networking:
driver failed programming external connectivity on endpoint:
Bind for 127.0.0.1:8978 failed: port is already allocated

Finden Sie den belegenden Prozess und weichen Sie aus:

# Welcher Prozess haelt den Port?
ss -tlnp | grep 8978

# Alternativ auf Containerseite suchen
docker ps --format '{{.Names}} {{.Ports}}' | grep 8978

Anschließend in der Compose-Datei auf einen freien Port wechseln, etwa 127.0.0.1:18978:8978. Die Angabe hinter dem Doppelpunkt bleibt unverändert, das ist der Port im Container.

Verbindung zur Datenbank schlägt fehl. Der mit Abstand häufigste Fall ist der Eintrag localhost als Host. Aus dem Container heraus zeigt das auf den Container selbst. Tragen Sie den Servicenamen ein, hier postgres. Prüfen lassen sich Namensauflösung und Erreichbarkeit direkt:

# Namensaufloesung im Compose-Netz pruefen
docker compose exec cloudbeaver getent hosts postgres

# Erreichbarkeit des Datenbankports pruefen
docker compose exec cloudbeaver bash -c "(exec 3<>/dev/tcp/postgres/5432) && echo erreichbar"

Bei einer externen Datenbank außerhalb von Docker ersetzen Sie den Servicenamen durch die IP-Adresse des Datenbankservers und stellen sicher, dass dessen Firewall den Container durchlässt.

Rechteprobleme am Volume. Meldet das Protokoll Fehler beim Schreiben in den Workspace, liegt das fast immer an einem Bind-Mount mit falschem Eigentümer. Kontrollieren Sie die Rechte im Container und korrigieren Sie sie auf dem Host:

# Rechte im Container ansehen
docker compose exec cloudbeaver ls -la /opt/cloudbeaver/workspace

# Bei einem Bind-Mount die Rechte auf dem Host korrigieren
sudo chown -R 1000:1000 /opt/stacks/cloudbeaver/workspace

Die passende Kennung entnehmen Sie der Ausgabe im Container. Ein benanntes Volume vermeidet das Problem von vornherein.

Container startet nicht oder beendet sich sofort. Sehen Sie zuerst in das Protokoll und prüfen Sie den Beendigungsgrund:

# Letzte Protokollzeilen
docker compose logs --tail 80 cloudbeaver

# Warum wurde der Container beendet?
docker inspect cloudbeaver --format '{{.State.ExitCode}} {{.State.OOMKilled}}'

Steht hinter OOMKilled ein true, ist dem Container der Arbeitsspeicher ausgegangen. Das passiert bei einer JVM typischerweise, wenn eine Abfrage eine sehr große Ergebnismenge liefert. Reduzieren Sie in diesem Fall CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT und geben Sie dem Container mehr Speicher.

Die Oberfläche antwortet kurz nach dem Start nicht. Das ist meist kein Fehler. Im Testlauf lieferte curl in den ersten rund 36 Sekunden den Code 000, also keine Verbindung, und erst danach HTTP 200. Warten Sie den Start ab und prüfen Sie im Protokoll, ob die Zeile über den gestarteten Jetty-Connector erschienen ist.

Saubere Deinstallation

Zum Entfernen genügen zwei Befehle. Der Unterschied zwischen ihnen entscheidet über Ihre Daten:

# Container und Netzwerk entfernen, Daten in den Volumes bleiben erhalten
docker compose down

# Image ebenfalls entfernen
docker image rm dbeaver/cloudbeaver:26.2.0

Warnung: Der folgende Befehl löscht unwiderruflich alle Daten. Das Anhängsel -v entfernt zusätzlich die Volumes. Damit sind der gesamte CloudBeaver-Workspace mit allen Benutzern und Verbindungen sowie die kompletten Inhalte der PostgreSQL-Datenbank verloren. Es gibt keinen Papierkorb und keine Rückfrage.

# ACHTUNG: loescht alle Volumes und damit saemtliche Daten unwiderruflich
docker compose down -v

# Kontrolle: es duerfen keine Volumes uebrig sein
docker volume ls --filter name=cloudbeaver

# Kontrolle: keine laufenden Container mehr
docker compose ps

Legen Sie vor diesem Schritt eine Sicherung an, falls auch nur die geringste Unsicherheit besteht. Der Aufwand dafür beträgt eine Minute, der Aufwand für die Rekonstruktion von Hand deutlich mehr.

Passende Anleitungen auf S-EDV

Quellen

CloudBeaverDocker ComposePostgreSQLDatenbank-ManagerSelfhostingReverse Proxy