sauber und dauerhaft lösen
Dateien die im Container als root erstellt wurden und auf dem Host nicht bearbeitbar sind, Volume-Mounts die Lese- oder Schreibzugriff verweigern, Prozesse die mit UID 0 laufen obwohl das nicht nötig wäre – Docker Dateirechte sind eines der häufigsten Probleme in der täglichen Entwicklung und im Produktionsbetrieb. UID/GID-Mapping, fixuid und rootless Docker lösen diese Konflikte systematisch.
Inhaltsverzeichnis
- 1. Wie Docker Dateirechte und UID/GID-Mapping funktionieren
- 2. Das klassische Berechtigungsproblem mit Bind Mounts
- 3. Das --user-Flag: einfachste Lösung für viele Fälle
- 4. Dockerfile: Benutzer und Rechte von Anfang an richtig setzen
- 5. fixuid: dynamische UID/GID-Anpassung im Container
- 6. Named Volumes vs. Bind Mounts: wann was verwenden
- 7. userns-remap: systemweite UID-Isolation
- 8. Rootless Docker: der sicherste Ansatz
- 9. Ansätze im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Wie Docker Dateirechte und UID/GID-Mapping funktionieren
Docker-Container teilen sich den Kernel des Hosts, aber nicht die Benutzer-Namespace. Das bedeutet: Die numerische UID 1000 im Container ist dieselbe UID 1000 auf dem Host-System – es gibt keine automatische Übersetzung. Wenn ein Prozess im Container als UID 0 (root) läuft und eine Datei auf einem gemounteten Volume schreibt, wird diese Datei auf dem Host ebenfalls als root-owned angelegt. Der lokale Entwickler mit UID 1000 kann sie dann nicht mehr bearbeiten, weil die Dateiberechtigungen 640 oder 600 mit root als Eigentümer gesetzt sind.
Dieses Verhalten ist kein Bug, sondern das korrekte Funktionieren des Linux-Berechtigungssystems. Docker Dateirechte-Probleme entstehen immer dort, wo die UID des Prozesses im Container nicht mit der UID des Benutzers auf dem Host übereinstimmt, der die Dateien öffnen oder bearbeiten möchte. Das tritt besonders bei Bind Mounts auf – wenn also ein Verzeichnis vom Host in den Container gemountet wird. Die Lösung liegt im UID/GID-Mapping: Container-Prozesse müssen mit derselben UID laufen wie der Host-Benutzer, der die Dateien besitzt, oder die Berechtigungen müssen explizit so gesetzt werden, dass alle Parteien schreiben können.
2. Das klassische Berechtigungsproblem mit Bind Mounts
Das typische Szenario: Ein Entwickler mountet sein lokales Projektverzeichnis als Bind Mount in einen PHP- oder Node-Container. Im Container wird ein Build oder ein Installationsschritt ausgeführt, der neue Dateien erzeugt. Die neuen Dateien gehören der UID des Prozesses im Container – häufig UID 0 (root) oder einer anderen festen UID, die im Dockerfile mit USER gesetzt wurde. Danach kann der lokale Entwickler diese Dateien nicht mehr mit seinem Editor bearbeiten oder per git committen, weil die Docker Dateirechte ihn ausschließen.
Das Problem verschärft sich, wenn CI/CD-Pipelines dasselbe Image verwenden. In der Pipeline läuft der Container als UID 0, der Build erzeugt Dateien als root, und die anschließende Stage, die als unprivilegierter Benutzer läuft, kann die Dateien nicht lesen. Solche Docker Dateirechte-Fehler in CI sind schwer zu debuggen, weil sie umgebungsabhängig sind und lokal oft nicht auftreten – dort läuft der Container ebenfalls als root. Die Grundursache ist immer dieselbe: die UID des Container-Prozesses stimmt nicht mit der UID des erwarteten Dateieigentümers überein.
# Diagnose: check which UID a container process runs as
docker run --rm nginx id
# uid=0(root) gid=0(root) — runs as root, will create root-owned files
# Check file ownership after writing to a bind mount
docker run --rm -v "$(pwd):/workspace" node:20 \
sh -c "npm install"
ls -la node_modules/
# drwxr-xr-x root root node_modules/ <- owned by root, not by your user
# Quick fix: explicitly pass host UID/GID to the container process
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$(pwd):/workspace" \
-w /workspace \
node:20 npm install
ls -la node_modules/
# drwxr-xr-x 1001 1001 node_modules/ <- owned by your host user
3. Das --user-Flag: einfachste Lösung für viele Fälle
Das --user-Flag beim docker run-Aufruf ist die direkteste Methode, um Docker Dateirechte-Probleme zu beheben. Mit --user $(id -u):$(id -g) läuft der Container-Prozess mit der UID und GID des aktuell eingeloggten Host-Benutzers. Dateien, die der Prozess schreibt, gehören dann dem Host-Benutzer und sind für ihn direkt zugänglich. In Docker Compose kann dasselbe mit der user-Direktive erreicht werden, entweder als statischer Wert oder als Umgebungsvariable.
Das --user-Flag hat jedoch eine wichtige Einschränkung: Der Benutzer mit der angegebenen UID muss im Container existieren oder die Anwendung darf keine Benutzer-spezifischen Konfigurationen (Home-Verzeichnis, Passwortdatei) benötigen. Viele Anwendungen schreiben beim Start in ihr Home-Verzeichnis oder lesen aus /etc/passwd. Wenn die UID nicht in /etc/passwd eingetragen ist, schlagen diese Operationen fehl. Das ist der Grund, warum das Flag allein nicht immer ausreicht und Ansätze wie fixuid notwendig werden.
4. Dockerfile: Benutzer und Rechte von Anfang an richtig setzen
Die sauberste Grundlage für korrekte Docker Dateirechte entsteht bereits im Dockerfile. Ein dedizierter nicht-root-Benutzer wird mit RUN addgroup und adduser angelegt, bekommt Zugriff auf alle Anwendungsverzeichnisse und wird als Standardbenutzer für den Container-Prozess gesetzt. Das USER-Statement im Dockerfile sorgt dafür, dass alle nachfolgenden RUN-, CMD- und ENTRYPOINT-Befehle mit diesem Benutzer ausgeführt werden. In Multi-Stage-Builds wird der nicht-root-Benutzer üblicherweise in der finalen Stage definiert, nachdem alle Build-Schritte, die root-Zugriff benötigen, abgeschlossen sind.
Eine häufige Falle beim Thema Docker Dateirechte im Dockerfile: Verzeichnisse werden als root erstellt und dann der Benutzer gewechselt, ohne die Eigentümerschaft der Verzeichnisse zu übertragen. Der Container-Prozess kann dann nicht in seine eigenen Arbeitsverzeichnisse schreiben. Das korrekte Muster ist: COPY --chown=user:group und RUN mkdir ... && chown user:group dir immer vor dem USER-Statement ausführen, solange der Build noch als root läuft.
# Dockerfile — proper user setup for correct file permissions
FROM php:8.4-fpm-alpine
# Create application user with fixed UID/GID matching typical host user
RUN addgroup -g 1000 -S appgroup && \
adduser -u 1000 -S appuser -G appgroup
# Install dependencies as root before switching user
RUN apk add --no-cache git
WORKDIR /var/www/html
# Copy files and set ownership in a single layer (no extra chown layer)
COPY --chown=appuser:appgroup . .
# Create writable directories and hand them to appuser
RUN mkdir -p var/cache var/log pub/media && \
chown -R appuser:appgroup var/ pub/
# Switch to non-root user — all subsequent commands run as appuser
USER appuser
# Verify: image must never run as root in production
# docker run --rm myimage id -> uid=1000(appuser) gid=1000(appgroup)
5. fixuid: dynamische UID/GID-Anpassung im Container
fixuid ist ein kleines Go-Programm, das beim Container-Start die UID und GID des Container-Benutzers auf eine extern übergebene UID/GID umschreibt. Das Ergebnis: Der Container-Prozess läuft mit der UID des Host-Benutzers, ohne dass das Image für jeden Entwickler neu gebaut werden muss. fixuid wird als Entrypoint-Wrapper eingesetzt und liest die gewünschte UID aus der FIXUID-Umgebungsvariable oder aus dem --user-Flag.
Dieser Ansatz ist besonders für Team-Entwicklungsumgebungen wertvoll, wo verschiedene Entwickler unterschiedliche UIDs haben. Mit fixuid kann jeder Entwickler dasselbe Docker-Image verwenden und bekommt trotzdem korrekte Docker Dateirechte auf alle gemounteten Dateien. Die Konfiguration erfolgt in einer config.yml-Datei, die ins Image kopiert wird und die Standard-UID und -GID sowie die Pfade definiert, deren Eigentümerschaft beim Start angepasst werden soll. Im Compose-File wird dann user: "${UID}:${GID}" gesetzt, wobei UID und GID aus der lokalen Shell-Umgebung kommen.
6. Named Volumes vs. Bind Mounts: wann was verwenden
Named Volumes und Bind Mounts verhalten sich grundlegend unterschiedlich bezüglich Docker Dateirechte. Bei einem Bind Mount wird ein Host-Verzeichnis mit allen seinen bestehenden Berechtigungen und Eigentümerschaften in den Container gemountet. Bei einem Named Volume erstellt Docker ein verwaltetes Verzeichnis, das zunächst leer ist und dessen Initialbefüllung beim ersten Container-Start aus dem Image-Layer erfolgt. Named Volumes gehören Docker und werden in einem von Docker verwalteten Bereich auf dem Host gespeichert.
Für Anwendungsdaten, die nur im Container gebraucht werden (Caches, generierte Assets, Datenbank-Dateien), sind Named Volumes die bessere Wahl, weil sie keine Docker Dateirechte-Konflikte mit dem Host-Benutzer erzeugen. Für Quellcode, den der Entwickler lokal bearbeiten und direkt im Container testen möchte, sind Bind Mounts notwendig. In diesem Fall ist explizites UID-Mapping oder fixuid erforderlich. Eine elegante Hybrid-Strategie kombiniert einen Bind Mount für den Quellcode mit Named Volumes für Schreibverzeichnisse wie var/cache oder vendor, die der Container exklusiv verwaltet.
7. userns-remap: systemweite UID-Isolation
User Namespace Remapping (userns-remap) ist eine Docker-Daemon-Konfiguration, die systemweit alle Container-UIDs auf einen verschobenen Bereich des Host-UID-Raums abbildet. Mit "userns-remap": "default" in der Docker-Daemon-Konfiguration wird beispielsweise UID 0 im Container auf UID 100000 auf dem Host gemappt. Das bedeutet: Selbst wenn ein Container-Prozess root-Rechte hat, sind seine Dateien auf dem Host im UID-Bereich 100000-165535 und haben damit keinerlei Zugriff auf Host-Dateien.
userns-remap löst ein wichtiges Sicherheitsproblem mit Docker Dateirechten: Container-Prozesse, die aus ihrem Container ausbrechen, landen auf dem Host als unprivilegierte Benutzer mit hohen UIDs. Für Entwicklungsumgebungen hat userns-remap jedoch einen Nachteil: Bind Mounts verhalten sich unter userns-remap anders, und bestehende Volumes müssen neu initialisiert werden. In CI/CD-Umgebungen oder auf Shared-Hosts, wo viele Teams dieselbe Docker-Engine teilen, ist userns-remap eine wichtige Sicherheitsmaßnahme gegen Privilege-Escalation über Docker-Volumes.
# /etc/docker/daemon.json — enable user namespace remapping
{
"userns-remap": "default"
}
# After daemon restart: verify remapping is active
docker info | grep "Security Options"
# Security Options:
# userns
# Check mapped UIDs for a running container
cat /etc/subuid # shows the allocated range, e.g.: dockremap:100000:65536
# Named volume ownership under userns-remap
# Docker automatically adjusts volume ownership when userns-remap is active
docker volume create myapp_data
docker run --rm -v myapp_data:/data alpine stat /data
# should show uid=0 inside container = uid=100000 on host
# docker-compose.yml: user mapping is handled automatically under userns-remap
# No --user flag needed — root in container is unprivileged on host
services:
app:
image: myapp:latest
volumes:
- myapp_data:/var/www/html/var
volumes:
myapp_data:
8. Rootless Docker: der sicherste Ansatz
Rootless Docker ist eine Betriebsart, bei der der Docker-Daemon selbst ohne root-Rechte läuft. Jeder Benutzer kann eine eigene Docker-Instanz betreiben, die vollständig in seinem Benutzer-Namespace isoliert ist. Docker Dateirechte-Probleme mit Bind Mounts entfallen bei rootless Docker weitgehend, weil der Daemon mit der UID des Benutzers läuft und alle Container-Prozesse im Namespace dieses Benutzers operieren. Dateien, die ein Container-Prozess auf einem Bind Mount schreibt, gehören auf dem Host automatisch dem richtigen Benutzer.
Die Installation von rootless Docker erfordert einige Systemvoraussetzungen: newuidmap und newgidmap müssen installiert sein, und der Benutzer braucht Sub-UID- und Sub-GID-Einträge in /etc/subuid und /etc/subgid. Rootless Docker hat gegenüber klassischem Docker einige Einschränkungen: Bestimmte Netzwerk-Features, privilegierte Ports unter 1024 und einige Storage-Driver sind nicht verfügbar. Für die meisten Entwicklungs- und Produktions-Workloads sind diese Einschränkungen jedoch irrelevant, und rootless Docker bietet die sauberste Lösung für Docker Dateirechte-Probleme.
9. Ansätze im direkten Vergleich
Für Docker Dateirechte-Probleme gibt es mehrere Lösungsansätze, die sich in Aufwand, Sicherheit und Eignung für verschiedene Szenarien unterscheiden.
| Ansatz | Aufwand | Sicherheit | Empfehlung |
|---|---|---|---|
| --user $(id -u) | Minimal | Gut | Einfache Entwicklungssetups |
| Dockerfile USER + chown | Gering | Sehr gut | Produktion: immer |
| fixuid | Mittel | Gut | Team-Entwicklung, diverse UIDs |
| Named Volumes | Gering | Sehr gut | Interne Container-Daten |
| userns-remap | Hoch | Maximal | Shared Hosts, Security-kritisch |
| Rootless Docker | Mittel | Maximal | Neue Setups, CI/CD |
Die Empfehlung für die meisten Teams: Im Dockerfile immer einen nicht-root-Benutzer mit fester UID definieren und Named Volumes für alle Container-internen Schreibverzeichnisse verwenden. Nur für Quellcode-Bind-Mounts in der Entwicklung ist zusätzlich das --user-Flag oder fixuid nötig. Rootless Docker ist die langfristig sauberste Lösung und wird aktiv von Docker Inc. und Red Hat (Podman) gefördert.
Mironsoft
Docker-Sicherheit, Dateirechte-Architektur und sichere CI/CD-Setups
Docker Dateirechte dauerhaft im Griff?
Wir analysieren bestehende Docker-Setups auf Dateirechte-Probleme, implementieren sichere UID/GID-Strategien und rüsten bestehende Dockerfiles und Compose-Konfigurationen mit korrekten Benutzer-Konfigurationen nach.
Dockerfile-Audit
Analyse auf root-Prozesse, falsche Berechtigungen und unsichere Volume-Konfigurationen
UID/GID-Strategie
fixuid-Integration oder rootless Docker für Team-Entwicklungsumgebungen
Produktionshärtung
userns-remap, read-only Filesystems und Security-Scanning in CI-Pipeline integrieren
10. Zusammenfassung
Docker Dateirechte-Probleme entstehen, wenn die UID des Container-Prozesses nicht mit der UID des erwarteten Datei-Eigentümers auf dem Host übereinstimmt. Die grundlegendste Maßnahme ist, im Dockerfile immer einen nicht-root-Benutzer mit USER zu definieren und alle Anwendungsverzeichnisse mit chown vor dem Benutzerwechsel zu übergeben. Für Entwicklungsumgebungen mit Bind Mounts löst das --user $(id -u):$(id -g)-Flag oder fixuid das Problem, ohne das Image für jeden Entwickler anpassen zu müssen.
Named Volumes sind für alle Container-internen Schreibverzeichnisse vorzuziehen, weil sie keine Host-seitigen Docker Dateirechte-Konflikte erzeugen. Rootless Docker und userns-remap sind die sichersten Ansätze für Produktions- und Multi-Tenant-Umgebungen, weil sie sicherstellen, dass Container-Prozesse auf dem Host niemals mit echten privilegierten UIDs operieren. Die Kombination aus korrekten Dockerfiles, intelligenten Volume-Strategien und UID-Mapping deckt alle häufigen Berechtigungsprobleme ab.
Docker Dateirechte — Das Wichtigste auf einen Blick
Dockerfile-Basis
Immer USER mit fester UID setzen, Verzeichnisse vor USER-Wechsel per chown übergeben. Keine root-Prozesse in Produktion.
Entwicklungsumgebung
--user $(id -u):$(id -g) oder fixuid für Bind Mounts. Named Volumes für vendor, cache und generierte Dateien.
Named vs. Bind Mounts
Named Volumes für Container-interne Daten, Bind Mounts nur für Quellcode der lokal bearbeitet wird. Hybrid-Strategie kombiniert beide.
Produktionssicherheit
Rootless Docker oder userns-remap auf Produktionsservern. Verhindert Privilege-Escalation auch wenn Container-Breakout erfolgt.