Docker Compose Secrets statt Klartext-Umgebungsvariablen: Zugangsdaten in Self-Hosting-Projekten mit Dateirechten, .gitignore und kontrollierter Rotation richtig schützen
Viele Self-Hosting-Setups übergeben Datenbank-Passwörter und API-Schlüssel als Umgebungsvariablen. Diese Anleitung zeigt Schritt für Schritt, wie Docker Compose Secrets, das *_FILE-Pattern, restriktive Dateirechte, sichere Prüfungen und eine kontrollierte Rotation zusammenspielen.

Typische Probleme: Passwörter stehen unter environment, .env landet in Git, docker inspect zeigt Werte, Prozesse lesen ihre Umgebung und die Rotation bleibt ungeplant.
Diese Fehlerbilder sind in kleinen Self-Hosting-Umgebungen häufig. Docker Compose Secrets lösen nicht jedes Geheimnisproblem, trennen sensible Werte aber sauber von der Konfiguration und stellen sie nur ausgewählten Diensten als Dateien bereit. Für 2026 ist das die sinnvolle Best Practice für einen einzelnen Docker-Host ohne Swarm oder externen Secret Manager.
Warum .env-Dateien kein Secret-Speicher sind
Eine .env-Datei eignet sich für unkritische Werte wie Portnummern oder Image-Tags, nicht für Passwörter. Compose übergibt Werte häufig als Prozessumgebung an den Container, sichtbar über Inspektionsdaten, Prozessinformationen oder Fehlerberichte. Ein Eintrag in .gitignore reduziert Git-Leaks, verschlüsselt die Datei aber nicht und entfernt bereits veröffentlichte Git-Historie nicht.
- Keine Passwörter direkt unter
environmenteintragen. - Keine Geheimnisse in
.envablegen. - Keine echten Zugangsdaten in Beispielen dokumentieren.
- Bereits veröffentlichte Werte sofort widerrufen und ersetzen.
Was Docker Compose Secrets tatsächlich leisten
Ein Secret wird auf der obersten Compose-Ebene unter secrets definiert. Erst die zusätzliche Freigabe unter services macht es für einen Container verfügbar. Lokales Compose bindet die Quelldatei standardmäßig als Datei unter /run/secrets/<name> ein. Der Wert erscheint dadurch nicht als normale Umgebungsvariable.
Wichtige Grenze: Lokales Compose bind-mountet Secrets vom Host. Anders als Docker Swarm bietet es keinen verschlüsselten Control-Plane-Schutz. Die Hostdatei bleibt der Schutzanker.
| Methode | Speicherort | Grenze |
|---|---|---|
environment | Prozessumgebung | Über Inspektion/Diagnose sichtbar |
.env | Meist in Prozessumgebung | Kein Secret-Speicher, Risiko durch Git |
| Compose Secret | /run/secrets/name | Quelldatei bleibt auf Host |
| Swarm Secret | Datei im autorisierten Task | Benötigt Swarm-Modus |
Schritt 1: Verzeichnis und Secret-Datei sicher anlegen
Legen Sie Secrets außerhalb öffentlich erreichbarer Verzeichnisse an. Das Passwort wird verdeckt eingelesen, nicht als Klartext in den Befehl geschrieben, damit es nicht in der Shell-Historie landet.
cd /srv/mein-stack
install -m 700 -d secrets
umask 077
read -rsp "Neues Passwort: " DB_PASSWORD
printf '\n'
printf '%s' "$DB_PASSWORD" > secrets/db_password.txt
unset DB_PASSWORD
chmod 600 secrets/db_password.txt
stat -c '%a %U:%G %n' secrets/db_password.txt
Die letzte Zeile muss für die Quelldatei den Modus 600 zeigen, nur der Besitzer darf lesen und schreiben. Angaben wie uid, gid und mode in der langen Secret-Syntax wirken bei einer lokalen Datei anders als bei Swarm, weil Compose einen Bind-Mount verwendet. Entscheidend sind die Rechte der Quelldatei auf dem Host und ein passender Benutzer im Container.
Schritt 2: Git-Leaks mit .gitignore verhindern
Ignorieren Sie das gesamte Secret-Verzeichnis, eine leere Platzhalterdatei bleibt sichtbar. Eine bereits getrackte Datei wird durch .gitignore nicht automatisch aus Git entfernt.
# /srv/mein-stack/.gitignore
secrets/*
!secrets/.gitkeep
touch secrets/.gitkeep
git check-ignore -v secrets/db_password.txt
Zeigt git check-ignore keine Regel, nicht committen. War das Passwort bereits Teil eines Commits, reicht Löschen nicht: Wert sofort rotieren, Historie nur abgestimmt bereinigen.
Schritt 3: Secret auf oberster Ebene und am Dienst definieren
Dieses Beispiel startet PostgreSQL mit dateibasiertem Initialpasswort. Unten registriert die Definition die Hostdatei als Compose Secret, der Eintrag im Dienst gewährt ausschließlich db Zugriff. POSTGRES_PASSWORD_FILE ist das vom offiziellen PostgreSQL-Image unterstützte *_FILE-Pattern.
services:
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
volumes:
postgres_data:
secrets:
db_password:
file: ./secrets/db_password.txt
Ohne secrets: - db_password im Dienst wird die Datei dort nicht bereitgestellt. Kein weiterer Dienst sollte das Secret erhalten, wenn er es nicht benötigt (geringste Berechtigung).
Schritt 4: Das *_FILE-Pattern für weitere Apps nutzen
Compose liest die Datei nicht automatisch für die Anwendung ein. Software oder Entrypoint müssen eine *_FILE-Variable unterstützen, der Name ist anwendungsspezifisch. Immer die Image-Dokumentation prüfen. Typisches Schema:
services:
app:
image: registry.example.org/meine-app:tag
environment:
APP_DB_HOST: db
APP_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
Der Image-Name ist ein Platzhalter, durch ein geprüftes Image ersetzen. Unterstützt eine App nur APP_DB_PASSWORD, erzeugt bloßes Anhängen von _FILE keine Funktion, dann braucht es einen dokumentierten Entrypoint oder externen Secret Manager. Das Secret nicht per Shell-Konstruktion zurück in eine Umgebungsvariable kopieren, sonst geht der Vorteil verloren.
Schritt 5: Konfiguration prüfen, ohne Geheimnisse auszugeben
Prüfen Sie zuerst die Syntax ohne gerenderte Konfiguration auf dem Bildschirm. docker compose config --quiet validiert das Modell und gibt bei Erfolg nichts aus. --quiet ist für Protokolle und Support-Sitzungen die vorsichtigste Variante, weil keine interpolierten Werte ausgegeben werden.
docker compose config --quiet
docker compose up -d
docker compose ps
Nur Existenz und Lesbarkeit der Datei im Container prüfen, nicht ihren Inhalt:
docker compose exec db sh -c 'test -r /run/secrets/db_password && echo "Secret-Datei ist lesbar"'
- Kein
cat /run/secrets/db_passwordin gemeinsam sichtbaren Terminals ausführen. - Keine Secret-Werte in Tickets oder Chats kopieren.
- Keine vollständige Prozessumgebung an Support-Bundles anhängen.
Schritt 6: Secrets kontrolliert rotieren
Eine geänderte Quelldatei ändert nicht automatisch das Kennwort im Zielsystem. Zuerst die Zugangsdaten dort ändern, danach die Secret-Datei atomar ersetzen und den Dienst kontrolliert neu erstellen. Wartungsfenster einplanen.
- Aktuelles Backup erstellen und Wiederherstellung prüfen.
- Neues starkes Passwort verdeckt erzeugen oder aus Passwortmanager übernehmen.
- Passwort im Zielsystem sicher ändern.
- Neue Secret-Datei mit Modus
600atomar verschieben. - Nur betroffene Dienste neu erstellen.
- Healthcheck, Anmeldung und Logs prüfen.
- Altes Passwort erst nach Prüfung endgültig verwerfen.
cd /srv/mein-stack
umask 077
read -rsp "Rotiertes Passwort: " NEW_PASSWORD
printf '\n'
printf '%s' "$NEW_PASSWORD" > secrets/db_password.txt.new
unset NEW_PASSWORD
chmod 600 secrets/db_password.txt.new
mv secrets/db_password.txt.new secrets/db_password.txt
docker compose up -d --force-recreate db
docker compose logs --since 5m db
Die Kennwortänderung in PostgreSQL ist bewusst nicht als SQL-Befehl dargestellt, sie hängt vom Rollenmodell ab. Bei mehreren Diensten die Reihenfolge planen, ein unkoordinierter Wechsel verursacht sonst Verbindungsfehler.
Backups ohne neue Klartextkopien planen
Datenbackup und Secret-Backup haben unterschiedliche Zwecke. Ohne Zugangsdaten scheitert eine Wiederherstellung, eine unverschlüsselte Kopie des Projektordners vergrößert aber das Risiko. Secrets nur bei Bedarf sichern, getrennt und verschlüsselt.
- Secret-Verzeichnis aus unverschlüsselten Datei-Backups ausschließen.
- Benötigte Secrets in Passwortmanager oder verschlüsseltem Tresor sichern.
- Backup-Zugriffe protokollieren, auf wenige Konten begrenzen.
- Wiederherstellung regelmäßig in isolierter Umgebung testen.
- Nach möglichem Backup-Abfluss alle enthaltenen Secrets rotieren.
Vertiefend helfen Docker Compose absichern, Docker sicher aktualisieren und das Homepage-Dashboard-Beispiel.
Fazit: Bessere Trennung, aber kein Tresor
Compose Secrets halten sensible Werte aus Compose-Datei und Prozessumgebung heraus. Dateirechte, .gitignore und das *_FILE-Pattern bleiben Pflicht.