"Ich habe den Container aktualisiert – und jetzt sind alle Daten weg." Dieser Satz fällt in Selfhosting-Foren fast täglich. Die Ursache ist fast immer dieselbe: Die Daten lagen im Container statt außerhalb. Wer das Prinzip einmal verstanden hat, verliert nie wieder Daten durch Docker.
Das Grundprinzip: Container sind Wegwerfware
Ein Container ist wie ein frisch installiertes Programm aus einer Vorlage (dem Image). Bei jedem Update wird der alte Container gelöscht und aus dem neuen Image ein neuer gebaut. Alles, was im Container selbst gespeichert war, verschwindet dabei.
Deshalb gilt: Alle wichtigen Daten gehören in ein Volume – einen Speicherort außerhalb des Containers, der beim Neubau einfach wieder eingehängt wird.
Die drei Speicherorte
| Wo liegen die Daten? | Überlebt Update? | Leicht zu sichern? | |
|---|---|---|---|
| Im Container (kein Volume) | im Container-Dateisystem | nein | nein |
| Bind Mount | in einem Ordner deiner Wahl, z. B. ./data |
ja | sehr leicht |
| Named Volume | von Docker verwaltet unter /var/lib/docker/volumes/ |
ja | etwas umständlicher |
Bind Mounts – unsere Empfehlung für Einsteiger:innen
services:
app:
image: beispiel/app
volumes:
- ./data:/data
Links vom Doppelpunkt steht der Ordner auf deinem Server (hier data neben der docker-compose.yml), rechts der Pfad im Container. Du siehst die Dateien direkt, kannst sie kopieren und sichern – alles liegt zusammen im App-Ordner.
Named Volumes
services:
db:
image: postgres:16
volumes:
- dbdaten:/var/lib/postgresql/data
volumes:
dbdaten:
Docker verwaltet den Speicherort selbst. Das ist sauber und wird in vielen offiziellen Anleitungen genutzt. Anzeigen lassen sich die Volumes mit:
docker volume ls
docker volume inspect projektname_dbdaten
Woher weiß ich, welchen Pfad ich einbinden muss?
Die Dokumentation jedes Images nennt, wo die Anwendung ihre Daten ablegt (z. B. /data, /config, /var/lib/mysql). Genau diesen Pfad musst du einbinden. Bindest du einen falschen Pfad ein, läuft alles scheinbar – bis zum ersten Update.
Prüfen, was ein laufender Container tatsächlich eingebunden hat:
docker inspect CONTAINERNAME --format '{{ json .Mounts }}'
Diese Befehle können Daten löschen
| Befehl | Was passiert |
|---|---|
docker compose down |
Container weg, Volumes bleiben – harmlos |
docker compose down -v |
löscht auch die Named Volumes – Vorsicht! |
docker volume prune |
löscht alle Volumes, die gerade kein Container nutzt |
docker system prune --volumes |
räumt radikal auf, inklusive ungenutzter Volumes |
rm -rf ./data |
löscht den Bind-Mount-Ordner – wie jeder andere Ordner |
Bind Mounts werden von Docker-Befehlen nie gelöscht – ein weiterer Grund, warum wir sie für den Einstieg empfehlen.
Der zweite Klassiker: "Permission denied"
Bei Bind Mounts läuft das Programm im Container oft unter einer bestimmten Benutzer-ID (z. B. 1000). Gehört der Ordner auf dem Server jemand anderem, darf die Anwendung nicht schreiben.
- Viele Images (z. B. von linuxserver.io) bieten die Variablen
PUIDundPGIDan – setze sie auf deine eigene ID, die du mitidherausfindest. - Sonst den Ordner passend übergeben:
sudo chown -R 1000:1000 ./data(die richtige ID steht in der Doku des Images).
Backups
- Bind Mounts: den App-Ordner sichern, am besten bei gestopptem Container (
docker compose stop), damit keine halb geschriebenen Dateien im Backup landen. - Datenbanken: zusätzlich einen Export anlegen (z. B.
pg_dumpbzw.mysqldump) – das ist robuster als das rohe Datenverzeichnis. - Am einfachsten: Läuft Docker in einer Proxmox-VM, sichern die Proxmox-Backups die komplette VM samt aller Volumes.
Die drei Regeln zum Merken
- Jede Anwendung bekommt ein Volume für ihre Daten – vor dem ersten Start.
- Nach der Einrichtung einmal testen: Container mit
docker compose down && docker compose up -dneu bauen – sind die Daten noch da? - Kein
-vbeidocker compose down, wenn du nicht genau weißt, warum.
Mehr zu Docker: Docker und Docker Compose installieren.