Zum Inhalt

PostgreSQL per Docker installieren: Eigene Datenbank für selbstgehostete Dienste

Veröffentlicht am 8. Oktober 2026 · Geschätzte Lesezeit: 9 Minuten

PostgreSQL ist eine der am weitesten verbreiteten Open-Source-Datenbanken und wird von vielen selbstgehosteten Anwendungen als Backend benötigt – darunter Immich, Paperless-ngx, Authentik, Firefly III und NocoDB.[2][3] Statt PostgreSQL systemweit zu installieren, betreibst du es in einem Docker-Container. Das hält das Hostsystem sauber, erleichtert Versionswechsel und lässt sich mit Docker Compose in jeden Stack einbinden. Die Einrichtung dauert etwa 20 Minuten.[1][5]

Voraussetzungen

  • Ein Linux-Server (Ubuntu 22.04+, Debian 12) mit Docker Engine 24+ und Docker Compose v2
  • Terminal-Zugriff mit sudo-Rechten
  • Ausgehender Internetzugriff zu Docker Hub
  • Mindestens 512 MB freier Arbeitsspeicher, 1 GB freier Festplattenplatz für die Datenbank

1. Datenbank-Passwort festlegen

Lege ein sicheres Passwort für den PostgreSQL-Superuser (postgres) fest. Dieses Passwort wird später von allen Diensten verwendet, die sich mit der Datenbank verbinden:[3]

openssl rand -base64 24

Der Befehl erzeugt einen zufälligen String wie aB3xK9mPqR7vW2yL5nC8sT0uZfdE. Notiere den Wert – du brauchst ihn in Schritt 3 als Platzhalter für POSTGRES_PASSWORD.

Passwort sicher aufbewahren

Das PostgreSQL-Passwort schützt alle Datenbanken auf diesem Server. Speichere es in einem Passwort-Tresor (zum Beispiel Vaultwarden oder Bitwarden) und nicht in einer unverschlüsselten Textdatei.

2. Projektordner anlegen

Erstelle einen eigenen Ordner für die PostgreSQL-Konfiguration:[5]

mkdir -p ~/postgresql && cd ~/postgresql

In diesem Ordner liegen später die compose.yaml und eine .env-Datei mit den Zugangsdaten.

3. Umgebungsvariablen hinterlegen

Erstelle eine .env-Datei, die Docker Compose automatisch einliest. Ersetze <dein-postgres-passwort> durch den in Schritt 1 generierten Wert:

cat > .env << 'EOF'
POSTGRES_PASSWORD=<dein-postgres-passwort>
EOF

Bedeutung der Platzhalter:

Platzhalter Bedeutung
<dein-postgres-passwort> Passwort für den PostgreSQL-Superuser postgres

Die .env-Datei wird von Docker Compose automatisch eingelesen, sobald sie im selben Ordner wie die compose.yaml liegt.[4] Commite die Datei niemals in ein Git-Repository – füge sie stattdessen in eine .gitignore ein.

Weitere optionale Variablen

Mit POSTGRES_USER=meinuser änderst du den Namen des Superusers (Standard: postgres). Mit POSTGRES_DB=meinedb legst du eine初始Datenbank an, die beim ersten Start erstellt wird.[2][3] Beide Variablen haben nur beim ersten Start des Containers eine Wirkung.

4. docker-compose.yml erstellen

Erstelle die Datei compose.yaml im Projektordner:[1][5]

services:
  postgres:
    image: postgres:18
    container_name: postgres-db
    restart: unless-stopped
    ports:
      - "127.0.0.1:5432:5432"
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_USER=postgres
      - POSTGRES_DB=postgres
    volumes:
      - postgres_data:/var/lib/postgresql
      - ./init-db:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

Erklärung der wichtigsten Einstellungen:

Abschnitt Erklärung
image: postgres:18 Fixierte Hauptversion 18. Das Tag latest kann unerwartet die Hauptversion wechseln und die Datenbank unlesbar machen. Immer die Hauptversion angeben.[4]
restart: unless-stopped Startet den Container bei Server-Neustart oder Absturz automatisch, außer du stoppst ihn explizit.
ports: "127.0.0.1:5432:5432" Macht PostgreSQL nur auf localhost verfügbar – nicht aus dem Heimnetz. Für den Zugriff aus anderen Containern (siehe Schritt 9) ist kein Port nötig.[1]
volumes: postgres_data:/var/lib/postgresql Wichtig ab PostgreSQL 18: Das Datenverzeichnis liegt versioniert unter /var/lib/postgresql/18/docker. Durch das Mounten des Elternpfads /var/lib/postgresql bleiben die Daten beim Container-Neustart oder -Wechsel erhalten.[1][4] Bei PostgreSQL 17 und älter muss /var/lib/postgresql/data gemountet werden.
volumes: ./init-db:/docker-entrypoint-initdb.d Ein lokaler Ordner für Initialisierungsskripte, die beim ersten Start automatisch ausgeführt werden (optional).[2]
healthcheck Prüft alle 10 Sekunden mit pg_isready, ob die Datenbank bereit ist. Andere Container können mit depends_on: postgres: condition: service_healthy warten, bis PostgreSQL antwortet.[1]

PostgreSQL 18 – veränderter Datenpfad

Seit PostgreSQL 18 ist der standardmäßige Datenpfad nicht mehr /var/lib/postgresql/data, sondern die versionierte Struktur /var/lib/postgresql/18/docker. Ein Volume auf den alten Pfad gemountet führt dazu, dass PostgreSQL beim Start keinen Zugriff auf die vorhandenen Daten hat. Verwende bei PostgreSQL 18 immer /var/lib/postgresql als Ziel.[4]

5. Datenbank starten

Starte den Container mit Docker Compose:

cd ~/postgresql
docker compose up -d

Prüfe, ob der Container läuft:

docker compose ps

Die Ausgabe sollte postgres-db mit dem Status Up zeigen. Siehst du stattdessen Exit, lies die Logs:

docker compose logs postgres

Ein häufiger Fehler bei PostgreSQL 18 ist eine falsche Volume-Zielangabe – dann erscheint eine Meldung wie data directory ... is not empty oder permission denied.

6. Verbindung testen (innerhalb des Containers)

Der einfachste Weg, die Datenbank zu erreichen, ist über die psql-Konsole direkt im Container. Der Zugriff über die Unix-Socket-Verbindung benötigt kein Passwort:[2][6]

docker exec -it postgres-db psql -U postgres -d postgres

Du solltest die PostgreSQL-Eingabeaufforderung sehen:

psql (18.x)
Type "help" for help.

postgres=#

Gib folgenden Befehl ein, um zu prüfen, dass die Datenbank wirklich läuft:

SELECT version();

Verlasse die Konsole mit \q oder exit.

7. Datenbank von der Kommandozeile des Hosts nutzen

Wenn du Port 5432 auf 127.0.0.1 gebunden hast (siehe compose.yaml), kannst du von deinem Server aus mit jedem PostgreSQL-Client verbinden. Installiere psql auf dem Host, falls noch nicht geschehen:[4]

sudo apt update && sudo apt install -y postgresql-client

Dann verbinde dich:

psql -h localhost -p 5432 -U postgres -W postgres

Das Kennwort ist der Wert aus Schritt 1. Du bist jetzt mit derselben Datenbank verbunden wie in Schritt 6, nur über TCP statt über den Unix-Socket.

8. Erste Datenbank und Benutzer anlegen

Lege eine eigene Datenbank und einen dedizierten Benutzer für eine deiner Anwendungen an. Verbinde dich dazu per psql (wie in Schritt 6 oder 7) und führe folgende SQL-Befehle aus – ersetze <sicheres-app-passwort>, meinappuser und meinappdb durch eigene Werte:

CREATE USER meinappuser WITH PASSWORD '<sicheres-app-passwort>';
CREATE DATABASE meinappdb WITH OWNER meinappuser;
GRANT ALL PRIVILEGES ON DATABASE meinappdb TO meinappuser;

Bedeutung der Platzhalter:

Platzhalter Bedeutung
meinappuser Name des Datenbank-Benutzers für deine Anwendung
<sicheres-app-passwort> Eigenes Passwort für diesen Benutzer
meinappdb Name der Datenbank, die deine Anwendung verwenden wird

Automatische Initialisierung

Wenn du viele Datenbanken oder Benutzer regelmäßig anlegst, lege ein SQL-Skript im Ordner ./init-db an (siehe Schritt 4). Dieses Skript wird automatisch ausgeführt, sobald der Container zum ersten Mal mit einem leeren Datenverzeichnis startet.[2]

Erstelle dazu zum Beispiel die Datei init-db/01-create-app-user.sql – ersetze auch hier <sicheres-app-passwort> durch ein eigenes Passwort:

CREATE USER meinappuser WITH PASSWORD '<sicheres-app-passwort>';
CREATE DATABASE meinappdb WITH OWNER meinappuser;

9. Aus anderen Docker-Containern verbinden

Deine Anwendungs-Container müssen PostgreSQL nicht über den Host-Port erreichen. Binde sie stattdessen in dasselbe Docker-Netzwerk ein – dann ist PostgreSQL unter dem Dienstnamen postgres (oder postgres-db) erreichbar. Port 5432 muss dann gar nicht freigegeben werden.[1][5]

Ergänze in der compose.yaml deiner Anwendung:

services:
  meineapp:
    image: meineapp:latest
    networks:
      - postgres-network

networks:
  postgres-network:
    external: true

Erstelle dann das Netzwerk und binde PostgreSQL ein:

docker network create postgres-network

Füge in der PostgreSQL-compose.yaml das externe Netzwerk hinzu:

services:
  postgres:
    # ... bestehende Konfiguration ...
    networks:
      - postgres-network

networks:
  postgres-network:
    external: true

Starte beide Stacks neu:

cd ~/postgresql && docker compose up -d
cd ~/meineapp && docker compose up -d

Deine Anwendung kann sich jetzt unter der Verbindungszeichenfolge verbinden:

postgresql://postgres:***@postgres:5432/postgres

Der Hostname postgres entspricht dem Dienstnamen aus der compose.yaml und wird von Docker DNS automatisch aufgelöst.[1]

Platzhalter in der Verbindungszeichenfolge

Ersetze *** in der Verbindungszeichenfolge durch das Passwort aus Schritt 1. Die vollständige Verbindung lautet dann zum Beispiel postgresql://postgres:meinpasswort@postgres:5432/postgres.

10. Tägliche Wartung: Backup mit pg_dump

Regelmäßige Backups sind auch für eine Container-Datenbank wichtig. Lege ein einfaches Backup-Skript an, das täglich ein SQL-Dump erzeugt:[2]

mkdir -p ~/postgresql/backups
docker exec postgres-db pg_dump -U postgres --all-databases > ~/postgresql/backups/postgres-all-$(date +%F).sql

Das Kommando erstellt eine Datei wie postgres-all-2026-10-08.sql, die alle Datenbanken als SQL-Befehle enthält. Zur Wiederherstellung:

cat ~/postgresql/backups/postgres-all-2026-10-08.sql | docker exec -i postgres-db psql -U postgres

Backups regelmäßig testen

Ein Backup, das nie getestet wurde, ist kein Backup. Lege mindestens einmal im Monat einen leeren Container an und stelle das Dump darin wieder her. Wie das genau geht, zeigt der Artikel Backup-Wiederherstellung testen.

11. PostgreSQL aktualisieren

Die PostgreSQL-Hauptversion (z. B. 18 → 19) kann nicht durch einfaches Ändern des Image-Tags vollzogen werden. PostgreSQL erwartet eine exakte Übereinstimmung der Datenverzeichnis-Version. Für ein Hauptversions-Upgrade benötigst du pg_upgrade oder die offiziellen Upgrade-Skripte des Docker-Images:[4]

  1. Lege ein vollständiges Dump-Backup an (siehe Schritt 10).
  2. Stoppe den Container: docker compose down
  3. Lösche das alte Volume nur, wenn du das Dump gesichert hast: docker volume rm postgresql_postgres_data
  4. Ändere das Image-Tag in der compose.yaml.
  5. Starte den Container neu: docker compose up -d
  6. Spiele das Dump ein.

Alternativ betreibst du PostgreSQL außerhalb von Docker und nutzt den Container nur für die Dienste, die ihn brauchen – dann sind Updates Sache des Host-Paketmanagers.

12. Typische Fehler und Fehlerbehebung

Container startet nicht: „data directory ... is not empty" oder „permission denied"

Du hast das Volume auf den falschen Pfad gemountet. PostgreSQL 18 erwartet die Daten in einem versionierten Unterverzeichnis. Korrigiere das Volume-Ziel in der compose.yaml zu /var/lib/postgresql statt /var/lib/postgresql/data.[4]

„could not connect to server: Connection refused"

Der Container ist noch nicht fertig gestartet. Warte einige Sekunden oder prüfe mit docker compose logs postgres. Ein häufiger Anfängerfehler ist der Verbindungsversuch, bevor die Datenbank initialisiert ist – insbesondere beim ersten Start, der wegen initdb länger dauert.[2]

„FATAL: password authentication failed for user ‚postgres'"

Du versuchst, dich über TCP zu verbinden, aber das Passwort stimmt nicht. PostgreSQL 18 verwendet standardmäßig scram-sha-256 für TCP-Verbindungen. Prüfe, ob das Passwort in .env korrekt gesetzt ist und ob die .env-Datei tatsächlich im selben Ordner wie die compose.yaml liegt.[3]

Port 5432 ist bereits belegt

Wenn auf deinem Server bereits ein PostgreSQL oder ein anderer Dienst auf Port 5432 läuft, ändere den Host-Port in der compose.yaml, z. B. "127.0.0.1:5433:5432". Verbinde dich dann über Port 5433.[4]

Sources

[1] https://docs.docker.com/guides/postgresql/networking-and-connectivity — Docker Docs: PostgreSQL Networking and Connectivity [2] https://github.com/docker-library/docs/blob/master/postgres/content.md — Docker Library: Official PostgreSQL Image Documentation [3] https://hub.docker.com/_/postgres — Docker Hub: Official PostgreSQL Image [4] https://www.dbpro.app/blog/postgres-docker — DB Pro: Postgres Docker — The Complete 2026 Guide [5] https://docs.docker.com/guides/postgresql — Docker Docs: PostgreSQL Guide — Quick Start and Data Persistence [6] https://www.youtube.com/watch?v=Hs9Fh1fr5s8 — Caleb Curry: Run Postgres in a Docker Container (Easiest PostgreSQL Setup)

Fertig

Herzlichen Glückwunsch! Dein PostgreSQL-Datenbankserver läuft in einem Docker-Container und ist bereit für deine selbstgehosteten Anwendungen. Andere Docker-Dienste in deinem Netzwerk können sich unter postgres://postgres:DEIN_PASSWORT@postgres:5432/postgres verbinden.

Funktionsprüfung:

  1. docker compose ps – der Container postgres-db muss Up zeigen.
  2. docker exec postgres-db pg_isready -U postgres – die Antwort muss ...: accepting connections lauten.
  3. docker exec postgres-db psql -U postgres -c "SELECT 1;" – die Ausgabe muss eine Tabellenzeile mit 1 enthalten.
  4. Von einem anderen Container im selben Docker-Netzwerk: psql -h postgres -U postgres -W postgres – die Verbindung muss gelingen.

Solange alle vier Tests bestehen, arbeitet deine PostgreSQL-Datenbank einwandfrei.