Introduction

Après avoir monté un petit homelab qui grandit au fil du temps, j’ai naturellement commencé à avoir un certain nombre de machines dont quelques-unes qui hébergent des containers.

A cela s’ajoutent deux serveurs OVH qui me servent à d’autres choses (monitoring, mails et backup par exemple) et qui, eux aussi, hébergent quelques dockers.

Au fur et à mesure, cela devient de plus en plus compliqué et fastidieux de me tenir informé sur l’état de ces containers.

Hier soir en voulant ouvrir mon coffre VaultWarden, je me suis rendu compte qu’il ne fonctionnait plus et la raison était simple, il n’avait pas été mis à jour ni touché depuis fort longtemps car c’est un exemple assez parlant de « set and forget ».

En plus de rendre potentiellement vulnérable une partie de mon infrastructure, cette vérification manuelle et aléatoire me pose un souci sur le long terme. Il n’est pas envisageable de maintenir des machines à la main en comptant seulement sur ma bonne volonté et le fonctionnement de ma mémoire.

Aussi en suis-je venu à considérer WUD, autrement appelé What’s Up Docker. Ce projet propose une interface unique afin de monitorer l’état de vos containers, vous alerter en cas de mise à jour disponible voire même de faire la mise à jour à votre place.

Déployable facilement et léger, je l’ai rapidement installé afin de voir ce dont il est question. Ci-dessous un extrait de docker stats concernant les consommations.

CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
d92c2587a5a0   wud       0.13%     82.55MiB / 4.808GiB   1.68%     6.16MB / 4.44MB   43.2MB / 43.7MB   19

Comme le montre l’image (allègrement récupérée directement sur le site du projet), WUD s’appuie sur trois composants :

  • Les Watchers, qui permettent d’interroger les containers distants ou locaux
  • les registries, pour faire des requêtes directement sur des services comme AWS ECR
  • Les triggers, qui exécutent des actions lorsqu’une mise à jour est disponible

Schéma

Voyons rapidement le contexte de cette installation. Nous allons installer WUD sur une VM Proxmox. Cette VM a déjà d’autres services (dont des containers) et certaines applications sont exposées sur le net grâce à cloudflare. Alors oui c’est Américain , je n’ai pas le contrôle dessus et c’est embêtant mais ça reste plus pratique que de gérer tout ça chez moi avec ma vieille LiveBox 5 et mes connaissances limitées en réseau. En tout cas pour l’heure.

Côté réseau local, je souhaiterai monitorer une autre machine (VM Matrix). Cela se fera facilement puisqu’elle communique directement avec la VM WUD.

Le challenge, si l’on peut dire, sera d’installer un watcher sur le VPS qui communiquera avec la VM WUD. Une liaison VPN étant déjà existante sur une autre machine, je vais la réutiliser puis simplement créer une route.

Afin d’avoir accès aux informations des containers j’utiliserai docker-socket-proxy. En mettant quelques droits supplémentaires sur ce container il me permettra également de mettre à jour les projets depuis l’interface web.

Configuration

Hub et Proxy

Commençons par générer un mot de passe pour notre page web, puisqu’elle sera exposée et que cela doit être renseigné dans le docker compose.

En sortie vous aurez le type de format ci-dessous, auquel il faut doubler chaque signe $ dans le fichier que nous créerons juste après.

htpasswd -nib mick motdepasse
mick:$apr1$6VvnFecx$GhrB/RDxMTmtLS5wsCJRb.

Pour installer WUD sur notre VM nous avons le choix de le faire avec Docker ou bien Docker compose et je préfère la seconde option.

services:
  whatsupdocker:
    image: getwud/wud
    container_name: wud
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 3000:3000
    environment:
      - WUD_AUTH_BASIC_MICK_USER=mick
      - WUD_AUTH_BASIC_MICK_HASH=$$apr1$$6VvnFecx$$GhrB/RDxMTmtLS5wsCJRb.
      - WUD_WATCHER_NAS_HOST=192.168.1.56
      - WUD_WATCHER_NAS_PORT=2375
      - WUD_WATCHER_NAS_CRON=0 6,18 * * *
      - WUD_WATCHER_LOCAL_CRON=0 6,18 * * *
      - WUD_WATCHER_R3_HOST=10.50.0.2
      - WUD_WATCHER_R3_PORT=2375
      - WUD_WATCHER_R3_CRON=0 6,18 * * *
      - WUD_TRIGGER_SMTP_MAIL_HOST=mails.mondomaine.fr
      - WUD_TRIGGER_SMTP_MAIL_PORT=465
      - WUD_TRIGGER_SMTP_MAIL_USER=wud@mails.mondomaine.fr
      - WUD_TRIGGER_SMTP_MAIL_PASS=P@ssw0rdK1Tu3
      - WUD_TRIGGER_SMTP_MAIL_FROM=wud@mails.mondomaine.fr
      - WUD_TRIGGER_SMTP_MAIL_TO=admin@mondomaine.fr
      - WUD_TRIGGER_SMTP_MAIL_TLS_ENABLED=true
      - WUD_TRIGGER_DOCKER_UPDATE_AUTO=false
      - WUD_TRIGGER_DOCKER_UPDATE_PRUNE=true

Je colle ici la configuration finale qui consiste à :

  • définir le couple identifiant/mot de passe pour l’interface web
  • configurer les machines à monitorer et la fréquence à laquelle nous les interrogeons (tous les jours de 6h à 18h)
  • Définir le service d’envoi des mails
  • Créer une trigger permettant de mettre à jour manuellement les containers et supprimer les anciennes images

A partir de là, nous pouvons déjà joindre WUD sur l’IP locale (en http). Nous n’allons pas aller plus loin car le reverse proxy https sera géré par cloudflare plus tard.

Avant de pousser le premier proxy je vais ajouter une route réseau puisque je suis sur la machine. Cela se fait simplement avec la commande ip route add 10.50.0.2/32 via 192.168.1.37.

Maintenant que le hub est installé et la route mise en place nous allons déployer le docker-proxy sur la VM Matrix, qui pour rappel est sur le même réseau local que le hub. La configuration étant la même pour le VPS à l’exception de l’IP je vais me contenter de mettre les deux IP dans le même exemple.

services:
  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy:latest
    container_name: docker-socket-proxy
    restart: unless-stopped
    ports:
    #Pour la VM Matrix, nous mettons son ip locale
      - "192.168.1.56:2375:2375"
    #Pour le VPS distant, nous mettons son ip locale Wireguard
      - "10.50.0.2:2375:2375"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - CONTAINERS=1
      - IMAGES=1
      - INFO=1
      - PING=1
      - VERSION=1
      - POST=1
      - DELETE=1

Avec cette configuration le hub WUD sera en mesure de faire les mises à jour et de supprimer les ancienne images. Sans explicitement mettre à 1 des directives telles que NETWORKS,EXEC ou VOLUME, il ne sera malgré tout pas possible d’éxecuter des commandes, toucher au réseau ou aux volumes. Cela n’enlève pas le risque mais permet tout de même de le mitiger.

Wireguard

Je me suis demandé si je devais décrire la configuration d’un tunnel wireguard. En premier lieu je n’ai pas jugé cela nécessaire mais suite à la remarque judicieuse d’un ami je vais finalement me fendre d’une explication.

Sur le client comme sur le serveur nous installons le paquet puis générons une paire de clé, indispensable car c’est de cette manière que Wireguard authentifie les membres du réseau. Nous venons ensuite créer un fichier de configuration dans /etc/wireguard en prenant soin de renseigner les IP locales souhaitées ainsi que les paires de clés. j’ai rajouté quelques règles de routage et feint d’utiliser vi alors qu’en bon gros débutant je lui préfère nano. Ne me frappez pas, merci. Les règles ne servent qu’à réécrire l’ip de la source d’un paquet provenant de l’interface wireguard. Si le paquet provient de wg0 ET que sa source est 192.168.1.36 alors la source devient 10.50.0.1.

sudo apt install wireguard
wg genkey | tee privatekey | wg pubkey > publickey
vi /etc/wireguard/wg0.conf

[Interface]
Address = 10.50.0.1/32
PostUp =  iptables -t nat -A POSTROUTING -o %i -s 192.168.1.36/32 -j MASQUERADE
PostDown =  iptables -t nat -D POSTROUTING -o %i -s 192.168.1.36/32 -j MASQUERADE
ListenPort = 51821
PrivateKey = MaCléPrivéeServeur

[Peer]
PublicKey = MaCléPubliqueClient
AllowedIPs = 10.50.0.2/32
Endpoint = IP_PUBLIQUE_CLIENT:43356

Côté client la configuration est similaire et très simple, c’est ce que j’aime avec wireguard.

[Interface]
Address = 10.50.0.2/32
PrivateKey = MaCléPrivéeClient

[Peer]
PublicKey = MaCléPubliqueServeur
Endpoint = IP_PUBLIQUE_SERVEUR:51821
AllowedIPs = 10.50.0.1/32
PersistentKeepalive = 25

La configuration est prête, nous allons simplement durcir un peu les droits avant de finalement donner vie à notre interface puis la rendre active dès le démarrage. Nous vérifions enfin que le lien est en fonctionnement. Si des données apparaissent dans transfer received/sent et que le lastest handshake renvoit bien quelque chose alors c’est validé.

sudo chmod 600 /etc/wireguard/wg0.conf
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0
sudo wg show
interface: wg0
  public key: XXXXXXXX
  private key: (hidden)
  listening port: 59589
  
peer: XXXXXX
  endpoint: IP_PUBLIQUE:51821
  allowed ips: 10.50.0.1/32
  latest handshake: 44 seconds ago
  transfer: 54.22 MiB received, 47.14 MiB sent
  persistent keepalive: every 25 seconds

Nous sommes presque rendus, il ne reste qu’à créer un enregistrement côté cloudflare. Encore une fois nous pouvons faire cela de différentes manières. Un simple enregistrement DNS de type A avec le sous domaine, puis un reverse proxy Nginx par exemple pour passer le tout en HTTPS. Ou alors une solution de feignant, passer le tout via cloudflare et le laisser faire. J’utilise les deux solutions mais aujourd’hui je suis paresseux.

En premier lieu il faut créer un tunnel. La procédure est plutôt simple et très bien expliquée sur l’interface, je ne vais pas la décrire ici. Pour gérer ce tunnel il faut aller dans Tunnels & Mesh. Après l’avoir sélectionné il faut se rendre dans l’onglet Published application routes et en créer une nouvelle.

C’est simple comme bonjour, il suffit de renseigner le sous domaine que nous souhaitons créer et vers quelle application interne il va pointer. Je mets donc http://192.168.1.36:3000 et pouf, la magie opère.

J’ai What’s Up Docker qui tourne en HTTPS, avec authentification et mes trois machines sont monitorées.

Je reçois immédiatement les alertes mails.

From: wud@mondomaine.fr
To: admin@mondomaine.fr
Subject: New digest found for container mollysocket
Message-ID: <5fdd2baf-4833-2e19-154e-151354cdbf3d@mondomaine.fr
Content-Transfer-Encoding: quoted-printable
Date: Mon, 24 Aug 2026 11:31:09 +0000
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8

Container mollysocket running with digest sha256:aa0b2a55ad7605f8aea0241dfb=
5b3f6d4ded2d8aca64d6bfce47087115e8062f can be updated to digest =
sha256:ed5d8d252d0a34614b68eb11aec9dee20742ec20449208853ad376722887118c

Point d’attention

En cherchant comment intégrer WUD dans Grafana (via Prometheus) je me suis rendu compte que par défaut le /metrics est complètement exposé. Il n’y a rien dans la documentation qui me permette directement d’y remédier, aussi me semble-t-il que la solution de contournement se situe au niveau du serveur web :

  • Mettre un htaccess ou équivalent
  • Si vous passez par cloudflare, c’est gérable par l’ajout d’un policy “Zero Trust” sur l’URL

Par défaut il y a un watcher “local” qui surveille les containers présents sur la même machine que WUD. Ce dernier a disparu dès lors que j’ai ajouté d’autres watchers. Mettre l’option suivante dans le docker-compose a permis de le réactiver:

  • WUD_WATCHER_LOCAL_CRON=0 6,18 * * *

Conclusion

La simplicité de déploiement de cet outil ainsi que sa légerté en font des atouts certains. J’ai tout de même observé quelques bugs dans l’affichage qui m’ont forcé à revenir à la page d’accueil pour pouvoir sélectionner le menu et je ne trouve pas pratique de devoir modifier le docker-compose à chaque ajout de trigger ou watcher. N’ayant pas encore beaucoup de recul sur cet outil je vais en rester là pour le moment, mais une phrase dans la documentation a attiré mon attention. WUD is designed to integrate seamlessly with your favorite tools: Home Assistant, Prometheus, Grafana.

C’est tout pour cette fois, nous irons plus loin la prochaine fois en automatisant la mise à jour de certains containers et nous verrons comment intégrer WUD à Grafana.

Bonne journée à toutes et tous et merci de m’avoir lu.

Sources

What’s Up Docker https://getwud.github.io/wud/docs

Wireguard https://www.wireguard.com/quickstart/