Restarting (1) 23 seconds ago. Das ist alles, was docker ps über einen Container sagt, der gerade in einer Schleife stirbt. Die 1 in der Klammer ist der Rückgabewert, und sie heißt nur: nicht gut. Warum nicht gut, steht woanders. Es steht im Log, und zwar fast immer in der letzten Handvoll Zeilen: ein Tippfehler in der Umgebungsvariable, eine Datenbank, die noch nicht erreichbar war, ein Ordner, in den der Container nicht schreiben darf. Wer die Zeilen lesen kann, braucht die Suchmaschine meistens nicht mehr.
Darum geht es hier: wie du an die Logs deiner Container kommst. Zuerst im Terminal mit docker logs, weil das überall funktioniert und nichts installiert. Dann mit Dozzle, einem kleinen Container, der dir alle Logs aller Container live im Browser zeigt. Und am Ende der Teil, den fast alle auslassen, bis die Platte voll ist: die Log-Rotation.
docker logs, die im Alltag reichen (letzte Zeilen, live mitlesen, Zeitfenster, Zeitstempel, Suche), startest Dozzle per Compose als Log-Fenster im Browser und stellst Docker so ein, dass Logs nie wieder die Platte füllen. Dauer: rund 20 Minuten. Stufe: Standard (Docker und Kommandozeile im Groben bekannt). Stand: Dozzle 11.3.0, geprüft am 07-10-2026.
Wo Docker die Logs hinschreibt
Ein Container hat keine Log-Datei im klassischen Sinn. Das Programm darin schreibt einfach auf die Konsole, so wie ein Skript, das du im Terminal startest: normale Meldungen auf die Standardausgabe, Fehler auf die Fehlerausgabe. Docker fängt beide Ströme ab und legt sie auf dem Server ab, standardmäßig als JSON-Datei pro Container unter /var/lib/docker/containers/. Diesen Mechanismus nennt Docker den Logging-Treiber, und der Standardtreiber heißt json-file.
Alles, was danach kommt, liest nur aus dieser Ablage. docker logs tut es im Terminal, Dozzle tut es im Browser, beide sehen exakt dieselben Zeilen. Das erklärt auch den häufigsten Irrtum: Loggt ein Programm in eine eigene Datei statt auf die Konsole, sehen beide nichts. Dazu unten mehr.
Was du brauchst
- Einen Linux-Server mit Docker und Docker Compose. Die Grundlagen zur Compose-Datei stehen in der Docker-Compose-Anleitung für Einsteiger.
- Mindestens einen laufenden Container, an dem du üben kannst. Ich nehme Uptime Kuma als Beispiel; jeder andere tut es auch.
- Einen Benutzer, der Docker-Befehle ausführen darf (in der Gruppe
dockeroder persudo).
Prüfen, ob Docker da ist und dein Benutzer es ansprechen darf:
docker --version
docker compose version
docker psZwei Versionsnummern und eine Tabelle mit deinen Containern, dann passt alles. Kommt bei docker ps ein „permission denied", fehlt dein Benutzer in der Gruppe docker; dann setzt du vor jeden Docker-Befehl in diesem Beitrag ein sudo.
Diese Werte benutze ich im ganzen Beitrag. Ersetze sie durch deine:
- IP-Adresse des Servers:
192.168.178.20 - Übungs-Container:
uptime-kuma - Ordner für Dozzle:
~/dozzle - Dozzle-Port:
8080, Adresse im Browser alsohttp://192.168.178.20:8080 - Dozzle-Benutzer:
sakis
Schritt 1: docker logs im Terminal
Der Befehl braucht den Namen oder die ID des Containers. Beides steht in der Tabelle von docker ps, der Name ganz rechts. Gestoppte Container fehlen dort; die zeigt erst docker ps -a, und genau die sind oft die interessanten, weil ein abgestürzter Container gestoppt ist.
docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESDas ist die Kopfzeile; darunter folgt eine Zeile pro Container, auch pro gestopptem, mit seiner Kennung, dem Image, dem Startbefehl, dem Alter und ganz rechts dem Namen. Diese Zeilen drucke ich nicht ab, weil sie bei jedem anders aussehen: andere IDs, anderes Alter, andere Namen. Die Spalte STATUS ist der erste Hinweis. „Up 3 days" heißt läuft, bei Images mit eigenem Gesundheits-Check steht ein „(healthy)" dahinter; „Restarting (1)" heißt, Docker startet ihn immer wieder neu, weil er immer wieder mit Fehler endet; „Exited (0)" heißt sauber beendet. Mehr Diagnose gibt es hier nicht, dafür gibt es den nächsten Befehl.
Die Grundform zeigt das komplette Log von Anfang an. Bei einem Container, der seit Wochen läuft, sind das zehntausende Zeilen, also fast immer mit --tail, das nur die letzten n Zeilen holt:
docker logs --tail 100 uptime-kumaDu bekommst die letzten hundert Zeilen, so wie das Programm sie geschrieben hat; bei einem gesunden Container enden sie mit seiner letzten Routine-Meldung. Beim Container in der Schleife von oben stehen an derselben Stelle die Zeilen, die den Abbruch erklären, meist die letzten drei bis fünf vor dem Ende. Die liest du zuerst, nicht die ersten.
Vier Optionen decken den Rest des Alltags ab, alle aus der Referenz zu docker logs:
# live mitlesen, bis du Strg+C drückst
docker logs -f --tail 50 uptime-kuma
# nur die letzten 30 Minuten
docker logs --since 30m uptime-kuma
# mit Zeitstempel vor jeder Zeile
docker logs -t --tail 20 uptime-kuma
# nach einem Wort suchen
docker logs uptime-kuma 2>&1 | grep -i errorDas -f steht für follow: Der Befehl endet nicht, sondern bleibt dran und zeigt jede neue Zeile sofort. Das ist die Variante, mit der du einen Container beim Starten beobachtest, in einem zweiten Terminal, während du im ersten docker compose up -d tippst. --since nimmt relative Angaben wie 30m oder 2h und ebenso feste Zeitpunkte; --until ist das Gegenstück für das Ende des Fensters.
Der Suchbefehl hat eine Falle, die leise zuschnappt: docker logs gibt die Fehlerausgabe des Containers auch als Fehlerausgabe wieder aus, und grep liest nur die normale Ausgabe. Ohne das 2>&1, das beide Ströme zusammenlegt, findet die Suche nach „error" genau in den Zeilen nichts, die Fehler enthalten. Viele Programme schreiben nämlich alles auf die Fehlerausgabe, auch ihre harmlosen Meldungen.
Mit Compose geht dasselbe über den Dienstnamen, im Ordner der Compose-Datei. Die Optionen heißen gleich, nur dass der Befehl ohne Dienstnamen die Logs aller Dienste des Projekts vermischt, jede Zeile mit dem Dienstnamen vorne dran:
cd ~/uptime-kuma
docker compose logs -f --tail 50Damit kannst du im Grunde aufhören. Alles, was jetzt kommt, ist Komfort. Aber Komfort, den ich nicht mehr hergeben würde, wenn mehr als fünf Container laufen.
Schritt 2: Dozzle per Docker Compose starten
Dozzle ist ein Log-Fenster im Browser: links alle Container, rechts das Log des angeklickten, live, mit Suche. Es ist MIT-lizenziert, hat über 14.000 Sterne auf GitHub, und der Entwickler Amir Raminfar veröffentlicht in einem Tempo, bei dem ich beim Schreiben zweimal die Versionsnummer prüfen musste: 11.3.0 kam am 05-10-2026, einen Tag vor diesem Beitrag. Es speichert selbst keine Logs, sondern liest nur, was Docker ohnehin hat. Dafür braucht es genau einen Zugang, und der ist die eine Sache, die du bei diesem Container verstehen musst: den Docker-Socket.
Der Docker-Socket ist die Datei /var/run/docker.sock, über die jeder Docker-Befehl mit dem Docker-Dienst spricht. Wer diese Datei im Container eingehängt bekommt, kann alles, was docker auf dem Server kann, einschließlich neue Container mit Zugriff auf das ganze Dateisystem starten. Die Doku sagt es wörtlich: Der Socket gibt Dozzle „root-equivalent access to the host". Für ein Tool, das Logs liest, ist das viel Vertrauen. Ich gebe es, weil der Code offen liegt und das Tool nichts anderes tut; aber ich hänge Port 8080 deshalb nie ans Internet. Dazu in „Was am Ende eingestellt ist" mehr.
Ordner anlegen und hineinwechseln:
mkdir -p ~/dozzle
cd ~/dozzleDann die Compose-Datei. Editor öffnen, Inhalt einfügen, mit Strg+O und Enter speichern, mit Strg+X schließen:
nano compose.yamlservices:
dozzle:
image: amir20/dozzle:v11.3.0
container_name: dozzle
restart: unless-stopped
environment:
- DOZZLE_NO_ANALYTICS=true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
ports:
- 8080:8080Das ist das Beispiel aus der Dozzle-Doku mit drei Änderungen, die ich begründen kann:
- image: Die Doku nimmt
latest, ich nehmev11.3.0. Bei einem Projekt, das in einer Woche drei Versionen veröffentlicht, will ich selbst entscheiden, wann ein Update kommt. - DOZZLE_NO_ANALYTICS: Dozzle schickt standardmäßig anonyme Nutzungsdaten (Version, Betriebsmodus, Anzahl der Container) an den Entwickler. Keine Log-Inhalte und keine Container-Namen, sagt die Doku, und ich habe keinen Grund, das zu bezweifeln. Ich schalte es trotzdem ab, weil mein Homelab niemandem Bericht erstattet.
- ./data:/data: Die Doku nimmt ein von Docker verwaltetes Volume. Ich nehme einen Ordner neben der Compose-Datei, weil in Schritt 3 die Benutzerdatei dort hinein muss und ein Ordner dafür der einfachere Weg ist. Außer Einstellungen und Benutzern liegt hier nichts, die Logs selbst bleiben bei Docker.
Starten und prüfen:
docker compose up -d
docker compose psNAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
dozzle amir20/dozzle:v11.3.0 "/dozzle" dozzle 1 second ago Up Less than a second 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp„Up" in der Spalte STATUS, dann läuft es. Und weil wir gerade bei Logs sind, der erste echte Anwendungsfall des Beitrags:
docker logs dozzleDozzle schreibt seine Startmeldungen auf die Konsole wie jeder andere Container, und da steht, auf welcher Adresse es lauscht. Im Sandkasten dieser Redaktion antwortete Port 8080 vier Sekunden nach dem Befehl. Das ist die Sorte „läuft sofort", bei der ich kurz misstrauisch werde, aber hier gibt es wenig, das schiefgehen könnte: ein Prozess, ein Port, keine Datenbank.
Schritt 3: Der erste Start im Browser
Im Browser http://192.168.178.20:8080 öffnen. Bei einer frischen Installation begrüßt dich ein Einrichtungs-Assistent (Stand Dozzle 11.3), der die Dinge abfragt, die die meisten direkt nach der Installation ändern. Er hat sechs Schritte, und bei dreien davon würde ich bewusst Nein sagen.
Login: Dozzle prüft zuerst, ob /data auf einem Volume liegt (bei uns der Ordner data, also ja). Dann die Art der Anmeldung wählen: Dozzle-Konto, nicht „Mein Proxy" und nicht „OIDC". Es gibt auch „Ohne Anmeldung fortfahren"; das lasse ich links liegen, selbst im Heimnetz, weil hinter dieser Oberfläche der Docker-Socket hängt. Benutzername sakis und ein Passwort vergeben, die E-Mail-Adresse ist optional. Das Passwort braucht mindestens acht Zeichen; die Anmeldeseite, die nach dem Neustart kommt, heißt „Authentifizierung erforderlich", ihr Knopf „Anmeldung".Weiter geht es mit Konto erstellen. Direkt danach startet Dozzle neu und zeigt die Anmeldeseite; nach der Anmeldung geht der Assistent bei Aktionen und Shell weiter.
Aktionen und Shell: beide Schalter aus lassen. Sie heißen Starten, Stoppen und Neustarten sowie Shell.Actions erlaubt Starten, Stoppen, Löschen und Aktualisieren von Containern aus Dozzle heraus; Shell öffnet ein Terminal im Container. Beides will ich nicht in einem Log-Fenster haben.
Hosts: leer lassen; das ist für Agenten auf anderen Servern. Weiter geht es mit Nicht jetzt, und derselbe Knopf überspringt auch Dozzle Cloud.
Dozzle Cloud: überspringen. Das ist der Cloud-Dienst des Entwicklers für Benachrichtigungen und Log-Historie; nichts in diesem Beitrag braucht ihn.
Auto-Update: überspringen. Dozzle kann inzwischen andere Container nach Zeitplan aktualisieren; das ist ein eigenes Thema und gehört nicht in die Erst-Einrichtung. Solange Aktionen aus sind, ist der Schritt ohnehin gesperrt und wird übersprungen.
Neustart: Der letzte Schritt meldet „Alles erledigt" und „Nichts erfordert einen Neustart", weil der Neustart schon nach der Anmeldung lief; mit Fertig schließt du den Assistenten.



Der Shell-Weg für die Anmeldung, wenn du den Assistenten nicht magst oder ihn mit DOZZLE_DISABLE_SETUP_WIZARD=true in der Compose-Datei abgeschaltet hast. Er legt die Benutzerdatei an, aus der Dozzle die Anmeldung liest, data/users.yml, mit einem bcrypt-Hash statt Klartext-Passwort. Der Befehl fragt das Passwort ab, weil ich es nicht in die Shell-Historie schreiben will:
cd ~/dozzle
docker run -it --rm amir20/dozzle:v11.3.0 generate sakis --email sakis@example.com --name "Sakis" > data/users.ymlDanach in ~/dozzle/compose.yaml im Abschnitt environment des Dienstes dozzle diese Zeile ergänzen und den Container neu erstellen:
- DOZZLE_AUTH_PROVIDER=simpledocker compose up -dErfolgskontrolle für beide Wege: Die Seite neu laden, Dozzle verlangt Benutzername und Passwort. Nach der Anmeldung steht links die Liste deiner laufenden Container, darunter dozzle selbst und uptime-kuma. Ein Klick auf einen Namen, und das Log läuft rechts live durch, dieselben Zeilen wie bei docker logs -f, nur dass du jetzt zwischen Containern mit einem Klick wechselst statt mit einem neuen Befehl. Der kleine Moment, in dem der erste Container von selbst neue Zeilen nachschiebt, ist der, an dem ich mich jedes Mal kurz freue.
Was Dozzle standardmäßig nicht zeigt: gestoppte Container. Das ist laut FAQ so gewollt und lässt sich in den Einstellungen mit Show Stopped Containers ändern. Für die Fehlersuche würde ich das sofort einschalten, denn der Container, der abgestürzt ist, ist gestoppt, und genau sein Log willst du sehen.
Was am Ende eingestellt ist
Der Dienst läuft, jetzt der Teil, der den Unterschied zwischen „läuft" und „läuft in einem Jahr noch" macht.
1. Log-Rotation, die wichtigste Einstellung dieses Beitrags. Der Standardtreiber json-file hat laut Docker-Doku als Standard für die maximale Größe „-1 (unlimited)" und hält eine einzige Datei. Jeder Container schreibt also unbegrenzt, bis die Platte voll ist; ein geschwätziger Container schafft das in Wochen. Die Einstellung gehört in die Datei /etc/docker/daemon.json, die es bei einer frischen Installation oft noch nicht gibt. Editor mit Root-Rechten öffnen, Inhalt einfügen, speichern, schließen:
sudo nano /etc/docker/daemon.json{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Alle Werte stehen in Anführungszeichen, auch die 3; so verlangt es die Doku, und ohne sie startet Docker nicht. Die Wirkung: Eine Log-Datei wächst bis 10 Megabyte, dann fängt Docker eine neue an und behält höchstens drei. Pro Container sind das maximal 30 Megabyte, egal wie lange er läuft. Existiert die Datei schon mit anderem Inhalt, fügst du nur die beiden Schlüssel ein. Dann den Docker-Dienst neu starten und prüfen:
sudo systemctl restart docker
docker info --format '{{.LoggingDriver}}'Die Antwort ist json-file. Und jetzt der Satz aus der Doku, der die Einstellung bei den meisten wirkungslos macht: „Existing containers don't use the new logging configuration automatically." Die Rotation gilt nur für Container, die nach der Änderung erstellt werden. Deine laufenden behalten die alte, unbegrenzte Einstellung, bis du sie neu erstellst, in jedem Compose-Ordner einmal:
cd ~/uptime-kuma
docker compose up -d --force-recreate
docker inspect --format '{{.HostConfig.LogConfig}}' uptime-kuma{json-file map[max-file:3 max-size:10m]}Steht da map[] ohne Inhalt, läuft der Container noch mit der alten Einstellung. Das Neu-Erstellen ist für Container mit Volume harmlos, die Daten bleiben; das Log beginnt allerdings von vorn. Wer die Einstellung lieber pro Container setzt, statt global, nutzt in der Compose-Datei den Abschnitt logging mit denselben Schlüsseln als options; das überschreibt die Vorgabe aus der daemon.json für diesen einen Dienst.
2. Actions und Shell bleiben aus. Beide Schalter stehen laut Doku standardmäßig auf false, und der Assistent hat sie nicht angefasst. Actions macht aus dem Log-Fenster ein Verwaltungswerkzeug, in dem ein Klick auf „remove" den Container löscht, samt allem, was er nicht in ein Volume geschrieben hat. Die Doku sagt das klar; ich sage es trotzdem nochmal, weil der Knopf nah an „restart" liegt. Für Verwaltung gibt es Dockhand, für Logs reicht Lesen.
3. Port 8080 bleibt im Heimnetz. Wegen des Docker-Sockets gilt: keine Portfreigabe im Router, nie. Wer von unterwegs Logs lesen will, geht über VPN, zum Beispiel wg-easy. Hinter einem Reverse Proxy geht es auch, dann mit TLS und der Anmeldung aus Schritt 3; die Doku empfiehlt für diesen Fall zusätzlich einen Socket-Proxy, der nur die nötigen Zugriffe auf den Socket durchlässt. Das ist ein eigener Beitrag, kein Nebensatz.
4. Updates von Hand. Die Version steht in der Compose-Datei. Ein Update heißt: Tag ändern, docker compose up -d, fertig; die Release-Seite auf GitHub sagt dir, was sich geändert hat. Sichern musst du bei Dozzle fast nichts: Der Ordner data enthält die Benutzerdatei und die Einstellungen des Assistenten, die Logs liegen bei Docker und sind, der Rotation sei Dank, ohnehin vergänglich. Wer Logs länger als 30 Megabyte pro Container braucht, ist bei einem Log-Sammler mit Datenbank richtig, nicht bei Dozzle. Das ist keine Schwäche, das ist die Aufgabenteilung.
Wo es klemmt
docker logs zeigt nichts, obwohl der Container läuft. Dann schreibt das Programm in eine Datei im Container statt auf die Konsole. Dozzle hat dafür eine eigene Doku-Seite, und die Empfehlung dort ist die richtige: das Programm auf Konsolen-Ausgabe umstellen, fast jedes hat eine Option dafür. Erst wenn das nicht geht, hilft der Umweg über einen Hilfscontainer, der die Datei mit tail -F auf die Konsole spiegelt; das Beispiel dafür steht in derselben Doku-Seite.
grep findet nichts, obwohl die Zeile da steht. Das 2>&1 fehlt. Siehe Schritt 1; ich wiederhole es hier, weil der Fehler keine Fehlermeldung hat, nur eine leere Ausgabe, und eine leere Ausgabe sieht aus wie „kein Fehler im Log".
Dozzle hinter einem Reverse Proxy lädt die Logs nicht oder nur ruckweise. Dozzle streamt die Zeilen über eine offen gehaltene HTTP-Verbindung (Server-Sent Events), und manche Proxys puffern diesen Strom, bis er voll ist. Die FAQ nennt die Lösung für nginx: proxy_buffering off; und proxy_cache off; für den API-Pfad. Bei Traefik muss text/event-stream aus der Komprimierung ausgenommen werden.
Dozzle verbraucht CPU, obwohl kein Browser offen ist. Laut FAQ gewollt: Dozzle hält die Container-Statistiken nach dem letzten Browser-Besuch noch bis zu sechs Stunden am Laufen, damit die Kurven beim nächsten Öffnen nicht leer sind. Auf einem Raspberry Pi fällt das auf; abstellbar ist es nicht.
Die Platte war schon voll, bevor du hier gelandet bist. Dann zuerst nachsehen, welcher Container es war:
sudo du -sh /var/lib/docker/containers/*/ | sort -h | tail -5Die größten fünf Ordner, jeder eine Container-ID. docker ps -a --no-trunc ordnet die ID dem Namen zu. Mit der Rotation von oben passiert das danach nicht mehr; für die aktuelle Datei reicht es, den betroffenen Container mit --force-recreate neu zu erstellen, dann beginnt sein Log leer. Die Datei von Hand zu löschen, während der Container läuft, würde ich lassen: Docker hält sie offen, und der Platz wird dann erst beim nächsten Neustart wirklich frei.
Logs sind der Ort, an dem ein Container dir sagt, was los ist. Mit docker logs hörst du zu, mit Dozzle hörst du allen gleichzeitig zu, und mit der Rotation verhinderst du, dass das Zuhören irgendwann die Platte kostet. Welche Log-Zeile hat dir zuletzt den Abend gerettet, oder welche hast du zu spät gelesen? Schreib's in die Kommentare.
Wenn beim Lesen ein „Port belegt" aufgetaucht ist: Den Schuldigen findest du hier, und der Beitrag passt gut als nächster Schritt nach diesem.
Quellen
- Docker-Doku: docker container logs (Referenz)
- Docker-Doku: docker compose logs (Referenz)
- Docker-Doku: Logging-Treiber konfigurieren
- Docker-Doku: json-file-Treiber, max-size und max-file
- Dozzle-Doku: Getting Started
- Dozzle-Doku: Setup Wizard
- Dozzle-Doku: Simple Authentication
- Dozzle-Doku: Container Actions
- Dozzle-Doku: Analytics
- Dozzle-Doku: Log-Dateien auf der Platte
- Dozzle-Doku: FAQ
- Dozzle v11.3.0 auf GitHub (Release vom 05-10-2026)