← Retour au blog
·10 min

GUARDIAN : construire son propre dashboard de supervision Docker plutôt qu'installer Portainer

Jonathan Delhoux

Jonathan Delhoux

Développeur Fullstack, partenaire technique des agences web

Share →

GUARDIAN : construire son propre dashboard de supervision Docker plutôt qu'installer Portainer

Quand le homelab grandit, le SSH ne suffit plus

Mon homelab s'appelle higgins. C'est un MacBook Pro M3 reconverti en serveur 24/7, dont j'ai raconté la mise en place dans un précédent article. Depuis, il a bien vécu : un scraper de prospection avec son front et son back, une app photo familiale, un serveur mail de test, un reverse proxy Caddy. Six containers Docker qui tournent en permanence.

Et avec six containers, un problème nouveau apparaît : la supervision. Savoir si tout tourne, pourquoi un service ne répond plus, lire les logs d'un container qui plante au démarrage. Jusqu'ici, ma réponse c'était SSH. Une connexion, un docker ps, un docker logs -f, un docker compose restart. Ça fonctionne, mais ça suppose d'être devant un terminal. Depuis le canapé, depuis le téléphone, depuis le poste d'un client, c'est non.

Il me fallait un dashboard. Une page web qui montre l'état de tout, et qui permet d'agir : démarrer, arrêter, redémarrer, lire les logs en direct.

Le réflexe Portainer, et pourquoi je ne l'ai pas suivi

La réponse standard à ce besoin existe, elle s'appelle Portainer. C'est un excellent produit, des milliers de homelabs tournent avec. Je ne l'ai pas installé, pour trois raisons.

Mon besoin réel couvre 10 % de Portainer. Lister les containers, voir leur état de santé, leur CPU et leur RAM, les redémarrer, lire leurs logs. C'est tout. Portainer fait ça, plus la gestion de stacks, de volumes, de registries, d'équipes, de droits. Cette surface supplémentaire, je ne l'utiliserai jamais, mais je devrai la maintenir, la mettre à jour, et lui faire confiance.

Un dashboard de supervision a tous les droits. L'outil qui pilote vos containers a accès au socket Docker, donc à tout. Sur cette brique précise, je préfère un code que j'ai écrit et que je peux relire en entier, plutôt qu'un produit tiers dont je dois suivre les CVE.

Le sur-mesure ne coûte presque plus rien. C'est la suite logique de ce que je racontais dans mon article sur le self-hosting : avec les assistants IA, un outil interne ciblé se construit en quelques sessions de travail là où il aurait fallu des semaines il y a trois ans. Le calcul "produit existant vs sur-mesure" a basculé. Quand le besoin est petit et bien défini, le sur-mesure gagne.

Le résultat s'appelle GUARDIAN. Une app Nuxt 4 full-stack, dans un container comme les autres, qui supervise tous les autres.

L'architecture : volontairement minimale

  • Framework : Nuxt 4 full-stack. Front et API dans un seul container, même stack que le reste du homelab.
  • Accès Docker : dockerode sur le socket monté. L'API native du daemon, pas de CLI à embarquer dans l'image.
  • Logs temps réel : SSE (Server-Sent Events). Unidirectionnel, traverse le reverse proxy sans configuration.
  • Base de données : aucune. Tout l'état vient de l'API Docker, pourquoi le dupliquer ?
  • Authentification : basic auth au niveau de Caddy. Zéro code d'auth applicatif en phase 1.

Le principe de fonctionnement tient en trois flux :

  • Le front interroge l'API toutes les 5 secondes. Le serveur demande au daemon Docker la liste des containers, les inspecte (santé, politique de redémarrage, ports), et les regroupe par projet compose. Une card par application.
  • Les métriques CPU/RAM arrivent par un second endpoint, toutes les 10 secondes, chargées en différé.
  • Les actions (start, stop, restart) sont de simples POST qui appellent l'API Docker, suivis d'un rafraîchissement immédiat.

Pas de WebSocket, pas de state manager côté serveur, pas de file de jobs. Du polling assumé sur un dashboard interne consulté par une personne.

Trois problèmes plus intéressants que prévu

Un projet "simple" réserve toujours quelques surprises. Trois exemples qui valent le détour.

Les logs Docker sont un flux binaire multiplexé

Naïvement, on s'attend à ce que l'API logs renvoie du texte. En réalité, quand le container n'a pas de TTY alloué, Docker multiplexe stdout et stderr dans un seul flux binaire : chaque frame commence par un header de 8 octets qui indique le flux d'origine et la taille de la charge utile. Il faut démultiplexer avant d'envoyer quoi que ce soit au navigateur.

Côté front, un EventSource reçoit le flux en SSE : les 200 dernières lignes d'abord, puis le suivi en continu, avec filtre et autoscroll. À la fermeture du panneau, la connexion SSE se ferme et le serveur détruit proprement le stream Docker. Ce cycle de vie (ouvrir, suivre, nettoyer) est le vrai sujet du streaming de logs, bien plus que l'affichage.

Les stats CPU prennent deux secondes, et c'est normal

Premier réflexe en voyant l'endpoint de stats répondre en 2 secondes : chercher le bug. Il n'y en a pas. Pour calculer un pourcentage de CPU, le daemon Docker échantillonne les compteurs deux fois à une seconde d'écart, par container. C'est documenté, c'est incompressible.

La réponse n'est donc pas d'optimiser, mais de concevoir l'interface en conséquence : l'état des containers s'affiche immédiatement, les métriques arrivent ensuite, en différé, sans bloquer le reste. Un bon rappel que la performance perçue est une décision de design autant que de code.

Le bouton stop peut scier la branche sur laquelle il est assis

GUARDIAN tourne dans un container Docker, sur le daemon qu'il pilote. Donc l'interface affiche un bouton "Stop" pour... GUARDIAN lui-même. Cliquer dessus coupe le dashboard, qui ne peut alors plus se redémarrer, puisqu'il est éteint. Même problème en pire avec Caddy : le stopper fait tomber tous les domaines du homelab, y compris celui qui sert le dashboard.

La solution est triviale techniquement (une confirmation renforcée sur ces deux containers, et une commande SSH de secours documentée dans le README), mais le cas est représentatif d'une classe de problèmes réelle : tout outil d'administration qui s'administre lui-même a des angles morts. Mieux vaut les identifier avant de cliquer.

Le socket Docker monté, c'est root : assumer son modèle de menace

Il faut le dire clairement : monter /var/run/docker.sock dans un container équivaut à donner les droits root sur la machine. Qui contrôle le daemon contrôle les volumes de toutes les apps, peut monter n'importe quel chemin de l'hôte, lancer n'importe quelle image.

Plutôt que de prétendre que c'est anodin, le modèle de menace est posé et assumé :

  • Un seul point d'entrée authentifié : le domaine du dashboard passe par Caddy avec basic auth, mot de passe fort généré, hashé en bcrypt.
  • Exposition LAN uniquement : aucun port forwarding sur la box, rien ne sort du réseau local.
  • Secrets hors dépôt : le mot de passe vit dans un fichier ignoré par git et exclu du rsync de déploiement.
  • Surface d'API réduite : en phase 1, l'API ne sait faire que lister, inspecter, lire les logs et start/stop/restart. Pas d'exec dans les containers, pas de suppression, pas de création.

Ce dernier point est le plus important. La meilleure protection contre un endpoint dangereux, c'est de ne pas l'écrire. Le jour où le homelab sera partagé avec des tiers, il faudra durcir (auth applicative, ACL réseau). Ce jour n'est pas arrivé, et sur-sécuriser maintenant serait de la complexité spéculative.

Aller plus loin : la box internet dans le dashboard

Une fois la mécanique en place, l'étendre coûte peu. Deuxième onglet du dashboard : le réseau local. GUARDIAN est appairé à la Freebox via son API locale, et liste tous les appareils connectés : nom, IP, adresse MAC, signal wifi, dernière activité. Avec la permission adéquate, il peut même bloquer un appareil du wifi en un clic.

L'appairage avec une Freebox est un petit moment savoureux : l'application demande un token via l'API, et la validation se fait physiquement, en appuyant sur le bouton qui clignote en façade de la box. De l'authentification à deux facteurs dont le second facteur est "être dans le salon".

Dans la même veine, le dashboard gère maintenant l'accès aux autres apps du homelab par appareil. Le NAT du runtime Docker masquant les adresses IP clientes (le reverse proxy voit la même IP pour tout le LAN), impossible de filtrer par IP. La solution : des cookies d'enrôlement signés en HMAC, vérifiés par Caddy à chaque requête via forward_auth, avec une page d'enrôlement servie sur le domaine de chaque app. On bascule une app en accès restreint depuis le dashboard, effet immédiat, sans recharger quoi que ce soit.

Le détail qui change le quotidien : développer contre la vraie prod

Un dashboard Docker se développe mal contre un Docker local vide. Le socket étant configurable par variable d'environnement, un tunnel SSH suffit pour brancher l'environnement de dev local directement sur le socket du serveur. Le dashboard en développement sur le poste de travail affiche alors les vrais containers du serveur, leurs vraies métriques, leurs vrais logs.

Pas de fixtures, pas de mocks, pas d'environnement de staging à entretenir. Pour un outil interne, c'est le meilleur rapport confort/coût que je connaisse.

Ce que ce projet illustre

Au-delà du homelab, ce projet est un cas d'école de l'outil interne sur-mesure :

  • Un besoin précis vaut mieux qu'un produit générique. GUARDIAN fait exactement ce dont j'ai besoin, rien d'autre, et chaque ligne est relisible.
  • La phase 1 ne fait que de la lecture et des actions réversibles. Start, stop, restart, logs. Les opérations destructives viendront plus tard, ou jamais.
  • L'infrastructure existante fait le gros du travail. L'authentification est déléguée au reverse proxy, l'état vit dans l'API Docker, le déploiement réutilise les scripts rsync existants. Le code applicatif ne porte que la valeur ajoutée.

La suite est déjà planifiée : déclencher les rebuilds et redéploiements des apps directement depuis l'interface, avec la sortie de build streamée en SSE, et un historique des déploiements. La mécanique de streaming est déjà en place, il ne reste qu'à la brancher sur autre chose que des logs.

Si vous gérez une petite infrastructure (un homelab, les serveurs d'une agence, le parc applicatif d'une PME) et que les outils du marché vous semblent surdimensionnés, la question mérite d'être posée : et si l'outil exact que vous vouliez se construisait en quelques jours ?

Un projet d'outil interne, de dashboard ou de supervision sur-mesure ? Prenons contact. Des outils taillés sur votre besoin réel, sans la complexité des produits génériques.

/ Share this

Share →

[ Cookies ] Ce site utilise des cookies pour son fonctionnement et, avec votre accord, pour mesurer son audience. Consultez notre Politique de confidentialité.