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]
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]
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:
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:
Prüfe, ob der Container läuft:
Die Ausgabe sollte postgres-db mit dem Status Up zeigen. Siehst du stattdessen Exit, lies die Logs:
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]
Du solltest die PostgreSQL-Eingabeaufforderung sehen:
Gib folgenden Befehl ein, um zu prüfen, dass die Datenbank wirklich läuft:
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]
Dann verbinde dich:
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:
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:
Deine Anwendung kann sich jetzt unter der Verbindungszeichenfolge verbinden:
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]
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:
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]
- Lege ein vollständiges Dump-Backup an (siehe Schritt 10).
- Stoppe den Container:
docker compose down - Lösche das alte Volume nur, wenn du das Dump gesichert hast:
docker volume rm postgresql_postgres_data - Ändere das Image-Tag in der
compose.yaml. - Starte den Container neu:
docker compose up -d - 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:
docker compose ps– der Containerpostgres-dbmussUpzeigen.docker exec postgres-db pg_isready -U postgres– die Antwort muss...: accepting connectionslauten.docker exec postgres-db psql -U postgres -c "SELECT 1;"– die Ausgabe muss eine Tabellenzeile mit1enthalten.- 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.