Dozzle affiche les logs de vos conteneurs Docker dans un navigateur, en temps réel, sans rien installer sur l'hôte au-delà d'un conteneur de 15 Mo de mémoire. Là où docker logs -f vous condamne à un terminal par conteneur, Dozzle regroupe tout dans une interface unique, colore les niveaux de log, découpe l'écran et cherche par expression régulière.
C'est un visualiseur, pas une solution de journalisation. Il ne stocke rien, ne conserve rien, et ne cherche pas dans le passé. Ce guide installe la version 10.6.9 avec Docker Compose, puis traite le sujet que la plupart des tutoriels escamotent : Dozzle demande le socket Docker, et ce socket vaut un accès root sur votre machine.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer Dozzle avec Compose et suivre les logs de plusieurs conteneurs
- Restreindre ce que Dozzle expose, par label et par authentification
- Comprendre pourquoi monter le socket en
:rone protège de rien, preuve à l'appui - Isoler Dozzle du socket avec un proxy, et vérifier que ça marche
- Décider quand Dozzle suffit, et quand il faut une vraie stack de logs
Prérequis
Section intitulée « Prérequis »- Docker Engine 19.03 ou plus récent (API 1.40 minimum) et le plugin Compose. Voir le guide Docker.
- Un port libre pour l'interface. Ce guide utilise 8091.
- Le pilote de logs
json-file,localoujournald(le défaut de Docker convient).
Ce que Dozzle fait, et ce qu'il ne fait pas
Section intitulée « Ce que Dozzle fait, et ce qu'il ne fait pas »La distinction est fondamentale, et l'auteur du projet est le premier à la poser : Dozzle « ne stocke aucun fichier de log, il est conçu uniquement pour la consultation en direct ».
| Dozzle | Une stack de logs (Loki, ELK) | |
|---|---|---|
| Rétention | aucune, il lit le flux de Docker | des semaines ou des mois |
| Recherche passée | impossible | c'est sa raison d'être |
| Alerting | non | oui, avec corrélation |
| Coût | un conteneur de 15 Mo | plusieurs services, du stockage |
| Mise en route | deux minutes | une journée |
Autrement dit, Dozzle remplace docker logs -f sur plusieurs conteneurs à la fois. Il ne remplace pas Grafana Alloy et Loki, qui collectent, stockent et indexent. Sur un homelab, un poste de développement ou une petite infrastructure, c'est exactement ce qu'il faut. Dès qu'il faut retrouver ce qui s'est passé la semaine dernière, prouver une conformité ou déclencher une alerte, Dozzle n'est pas l'outil.
Étape 1 - Installer Dozzle
Section intitulée « Étape 1 - Installer Dozzle »Un fichier Compose suffit. Voici la version que nous allons construire pas à pas, avec deux conteneurs qui produisent de vrais logs pour avoir quelque chose à regarder.
services: dozzle: image: amir20/dozzle:v10.6.9 container_name: dozzle command: ["--no-analytics", "--filter", "label=lab=dozzle"] volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - dozzle_data:/data ports: - "8091:8080"
api: image: nginx:1.27-alpine container_name: lab-api labels: lab: dozzle ports: - "8092:80"
worker: image: alpine:3.21 container_name: lab-worker labels: lab: dozzle command: > sh -c "i=0; while true; do i=$$((i+1)); if [ $$((i % 5)) -eq 0 ]; then echo \"level=error msg=\\\"paiement refuse\\\" order=$$i\"; else echo \"level=info msg=\\\"commande traitee\\\" order=$$i\"; fi; sleep 2; done"
volumes: dozzle_data:docker compose up -dOuvrez http://localhost:8091/. Les logs défilent immédiatement.

Trois choses se voient sur cette capture. Dozzle colore les niveaux de log, en rouge les error et en vert les info, sans configuration. Il découpe les paires clé/valeur (level=, msg=, order=) et les met en évidence. Et il affiche en haut la consommation CPU et mémoire du conteneur, en direct.
Les deux options qui comptent dès l'installation
Section intitulée « Les deux options qui comptent dès l'installation »--no-analytics coupe la télémétrie. Dozzle envoie par défaut des données anonymes à chaque démarrage : version, mode de déploiement, nombre de conteneurs, plus un identifiant aléatoire par installation. Aucun contenu de log n'est transmis, l'auteur est clair là-dessus. Reste que c'est activé par défaut, et que le README parle encore de Google Analytics alors que le binaire ne contient plus aucune trace de Google : la destination réelle est b.dozzle.dev/event. La documentation est en retard sur le code, et cela vaut d'être su.
--filter label=lab=dozzle restreint Dozzle aux conteneurs qui portent ce label. Sans ce filtre, Dozzle affiche les logs de tous les conteneurs de la machine. Sur un serveur qui héberge autre chose, cela signifie exposer les journaux de votre base de données, de votre reverse proxy et de tout le reste dans la même interface.
Étape 2 - Le socket Docker, et le mensonge du :ro
Section intitulée « Étape 2 - Le socket Docker, et le mensonge du :ro »Vous avez remarqué le :ro à la fin du montage du socket. Des dizaines de tutoriels l'ajoutent en expliquant que Dozzle n'a besoin que de lire, et que le mode lecture seule garantit qu'il ne peut rien casser.
C'est faux, et la démonstration tient en une commande. Depuis un conteneur qui monte le socket en lecture seule, créons un conteneur via l'API Docker :
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro alpine:3.21 sh -c ' apk add --no-cache curl >/dev/null curl -s -o /dev/null -w "%{http_code}\n" -X POST --unix-socket /var/run/docker.sock \ -H "Content-Type: application/json" \ -d "{\"Image\":\"alpine:3.21\"}" \ http://localhost/containers/create'201HTTP 201 : le conteneur a été créé. En lecture seule.
L'explication est dans la nature d'un socket. Un fichier ordinaire s'écrit avec l'appel système write(), que le montage :ro bloque effectivement. Un socket, lui, communique avec send() et recv(), que le système de fichiers ne filtre pas. Le :ro empêche de supprimer le socket ou d'en changer les métadonnées, rien de plus. Les requêtes passent.
Étape 3 - Isoler Dozzle derrière un proxy de socket
Section intitulée « Étape 3 - Isoler Dozzle derrière un proxy de socket »La vraie parade est de ne jamais donner le socket à Dozzle. Un proxy de socket s'intercale, expose l'API Docker sur le réseau interne, et n'autorise que les points d'entrée dont Dozzle a besoin.
services: docker-socket-proxy: image: tecnativa/docker-socket-proxy:0.3.0 container_name: dozzle-socket-proxy environment: CONTAINERS: 1 # lister et lire les conteneurs INFO: 1 # nom d'hôte, version, CPU et RAM POST: 0 # aucune écriture volumes: - /var/run/docker.sock:/var/run/docker.sock:ro networks: - dozzle-net restart: unless-stopped
dozzle: image: amir20/dozzle:v10.6.9 container_name: dozzle command: ["--no-analytics"] environment: DOZZLE_REMOTE_HOST: tcp://docker-socket-proxy:2375|lab ports: - "8091:8080" networks: - dozzle-net depends_on: - docker-socket-proxy restart: unless-stopped
networks: dozzle-net:Dozzle n'a plus aucun volume, plus aucun accès au socket. Il parle au proxy en TCP, sur un réseau interne. Vérifions que la barrière tient, avec la même requête que tout à l'heure :
docker run --rm --network lab-dozzle_dozzle-net alpine:3.21 sh -c ' apk add --no-cache curl >/dev/null echo -n "POST /containers/create : " curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" \ -d "{}" http://docker-socket-proxy:2375/containers/create echo -n "GET /containers/json : " curl -s -o /dev/null -w "%{http_code}\n" http://docker-socket-proxy:2375/containers/json'POST /containers/create : 403GET /containers/json : 200403 sur la création, 200 sur la lecture. Là où le :ro renvoyait 201, le proxy refuse. La différence n'est pas cosmétique : le filtrage se fait au niveau de l'API, c'est-à-dire au seul endroit où il a un sens.
Un détail qui fait perdre du temps : Docker Compose préfixe le nom du réseau par celui du dossier, d'où le lab-dozzle_dozzle-net ci-dessus. Si votre projet s'appelle autrement, lisez le nom réel avec docker network ls.
Étape 4 - Fermer l'interface
Section intitulée « Étape 4 - Fermer l'interface »Par défaut, Dozzle n'a aucune authentification. La configuration exposée par l'interface le dit sans détour :
curl -s http://localhost:8091/ | grep -o '"authProvider":"[a-z-]*"'"authProvider":"none"N'importe qui atteignant le port lit tous vos journaux. Sur localhost, c'est sans conséquence. Dès que Dozzle sort de la machine, c'est inacceptable.
Dozzle sait générer un fichier d'utilisateurs, avec des mots de passe hachés en bcrypt :
-
Créez le compte et rangez le fichier dans un dossier monté :
Fenêtre de terminal mkdir -p datadocker run --rm amir20/dozzle:v10.6.9 generate \--password "UnMotDePasseSolide" --name "Stephane" --email "s@lab.local" admin > data/users.ymlLe fichier obtenu contient bien un hachage bcrypt, reconnaissable à son préfixe
$2a$:users:admin:email: s@lab.localname: Stephanepassword: $2a$11$JqB9QJC77f91I0AMFq9.ke... -
Activez le fournisseur d'authentification dans le service Dozzle :
environment:DOZZLE_AUTH_PROVIDER: simplevolumes:- ./data:/data -
Vérifiez que l'accès anonyme est bien refusé :
Fenêtre de terminal curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" http://localhost:8091/307 -> http://localhost:8091/login?redirectUrl=/
Dozzle sait aussi déléguer l'authentification à un proxy d'authentification (Authelia, oauth2-proxy, Cloudflare Access), via l'en-tête Remote-User. C'est la bonne approche si vous avez déjà un SSO, et cela permet d'attribuer à chaque utilisateur un filtre de conteneurs différent.
Sécurité : ce que 2026 a appris à Dozzle
Section intitulée « Sécurité : ce que 2026 a appris à Dozzle »Dozzle n'est plus le simple visualiseur en lecture seule d'il y a deux ans. Il sait, sur option, ouvrir un shell dans un conteneur (DOZZLE_ENABLE_SHELL) et piloter son cycle de vie (DOZZLE_ENABLE_ACTIONS). Ces surfaces ont un prix, et il a été payé.
| Vulnérabilité | Gravité | Nature | Corrigée en |
|---|---|---|---|
| CVE-2026-45298 | 8.6 | SSRF avant authentification sur le test de webhook | 10.5.2 |
| CVE-2026-44985 | 8.7 à 9.6 | Détournement de WebSocket sur /exec et /attach | 10.5.2 |
| CVE-2026-24740 | 8.7 | Contournement du filtrage par label en mode agent | 9.0.3 |
La deuxième mérite un mot, parce qu'elle frappait même avec l'authentification correctement configurée : le contrôle d'origine des WebSockets acceptait tout, et le cookie de session était en SameSite: Lax. Une page malveillante sur un sous-domaine voisin pouvait ouvrir un shell dans vos conteneurs.
La 10.6.9 installée ici corrige les trois. Deux réflexes en découlent. Laissez DOZZLE_ENABLE_SHELL et DOZZLE_ENABLE_ACTIONS désactivés : ce sont eux qui transforment un visualiseur en porte d'entrée. Et surveillez les versions, car un déploiement oublié sur une version d'il y a un an est aujourd'hui vulnérable.
Dépannage
Section intitulée « Dépannage »La plupart des problèmes de Dozzle ne viennent pas de Dozzle, mais de ce qu'il lit : le pilote de logs de Docker et le socket. Le tableau ci-dessous part du symptôme visible pour remonter à sa cause réelle.
| Symptôme | Cause | Correctif |
|---|---|---|
| Aucun log ne s'affiche | pilote de logs distant (splunk, fluentd, awslogs) avec cache-disabled: true | Dozzle lit l'API docker logs : réactiver le cache de double journalisation |
CPU et mémoire à 0 % | runtime non standard ou API distante | limitation connue selon le runtime, sans correctif |
| L'interface rame | plusieurs centaines de conteneurs | le goulot est le navigateur, pas le serveur ; filtrer par label |
host not found sous Podman | Podman ne génère pas d'engine-id | créer /var/lib/docker/engine-id avec uuidgen |
| L'interface s'ouvre sans mot de passe | authProvider: none par défaut | DOZZLE_AUTH_PROVIDER: simple et un users.yml |
| Dozzle voit des conteneurs qui ne le regardent pas | aucun filtre | --filter label=... |
À retenir
Section intitulée « À retenir »- Dozzle est un visualiseur de logs en direct, pas une solution de journalisation : aucune rétention, aucune recherche dans le passé.
- Il remplace
docker logs -fsur plusieurs conteneurs ; il ne remplace pas Loki ou ELK. - Le montage du socket en
:rone protège de rien : un socket répond àsend(), pas àwrite(). La preuve tient en une requête qui renvoie HTTP 201. - Le socket Docker vaut un accès root sur l'hôte. La vraie parade est un proxy de socket (403 en écriture, 200 en lecture) ou le mode agent.
- Aucune authentification par défaut :
authProvider: none. Unusers.ymlen bcrypt ou un proxy d'authentification s'impose dès que Dozzle sort delocalhost. - Sans
--filter, Dozzle expose les logs de tous les conteneurs de la machine. - La télémétrie est active par défaut :
--no-analyticsla coupe. Le README parle de Google Analytics, le binaire n'en contient plus trace. - Trois vulnérabilités sérieuses ont été corrigées en 2026, toutes sur les surfaces
/exec,/attachet webhook. Laissez le shell et les actions désactivés. - Épinglez la version.
latestsur un service exposé n'est pas une stratégie.