
🌐 Aussi en: English · Deutsch · Español
La version v3.6.0 du code Ansible qui fait tourner ce blog et deux serveurs Nextcloud est publiée. C’est la dernière version avec de nouvelles fonctionnalités avant un moment : désormais, la priorité va à la maintenance. Le fil conducteur de ces derniers jours : presque tous les bugs des semaines passées étaient passés inaperçus, parce que les contrôles demandaient « est-ce configuré et en marche ? » au lieu de « est-ce que ça marche vraiment ? ». Cette version change cela.
📦 Le téléchargement qui s’arrêtait à 1 Go
Le bug le plus récent est apparu ce matin, et pas grâce à un test : un e-mail d’alerte signalait qu’un conteneur était bridé en CPU plus de la moitié du temps. Il s’agissait du nginx placé devant PHP sur l’un des serveurs Nextcloud – un composant qui, d’habitude, ne fait presque rien.
Derrière, un utilisateur essayait de télécharger une archive de 13 Go. Chaque tentative s’arrêtait vers 1,08 Go. Deux valeurs par défaut se rencontraient : l’ingress met la réponse en tampon dans un fichier temporaire d’au plus 1 Go, puis cesse de lire depuis le pod jusqu’à ce que le client rattrape son retard. Le nginx du pod attend 60 secondes sans progression, puis ferme la connexion. Le client reçoit un fichier tronqué, et l’ingress journalise « upstream prematurely closed ». Les horodatages concordaient sur trois tentatives d’affilée : 1 Go en quelques secondes, puis exactement 67 secondes de silence.
La correction tient en une annotation, qui fait transmettre les données au rythme du client au lieu de remplir un fichier temporaire :
nginx.org/proxy-max-temp-file-size: "0"L’alerte CPU n’était qu’un effet secondaire : copier 1 Go en quelques secondes a brièvement amené au plafond un conteneur limité à 0,5 cœur.
À retenir : deux valeurs par défaut raisonnables peuvent produire un bug ensemble. Une alerte sur un symptôme mérite qu’on la suive, même quand le symptôme paraît anodin.
🧪 Des tests qui vérifient l’effet
Les rôles de vérification testent désormais ce qu’un composant doit accomplir, et pas seulement sa présence :
- Chaîne de bannissement : pour chaque jail fail2ban, une adresse de documentation (TEST-NET) est bannie, doit apparaître dans le bon ensemble du pare-feu, est débannie et doit disparaître. Deux jails bannissent la même adresse, l’une la libère – l’autre bannissement doit rester.
- Filtres : une ligne de journal préparée, au format actuel, passe dans
fail2ban-regexpour chaque jail. Un changement de format ne peut plus rendre une jail aveugle sans que personne ne le voie. - Présence des données : les métriques clés doivent exister, et aucune règle d’alerte Grafana ne doit rester en erreur ou sans données.
- Domaines SELinux : chaque démon de l’hôte doit tourner dans son propre domaine. « active (running) » dans le mauvais domaine compte comme un échec.
À retenir : « configuré et en marche » est un état. « Est-ce que ça marche » est un test, avec une entrée et un résultat attendu.
💓 Signaux de vie et chemin des e-mails
Certaines pannes sont silencieuses : une tâche nocturne qui ne tourne plus n’envoie jamais d’erreur. Chaque tâche périodique – AIDE, rkhunter, ClamAV, mises à jour automatiques, notifications de connexion et de bannissement – écrit désormais un horodatage sous forme de métrique quand elle se termine. Si une tâche est en retard, Grafana alerte.
Cela n’a de sens que si les e-mails d’alerte arrivent. Une règle se déclenche donc volontairement chaque semaine ; si cet e-mail manque, le chemin des e-mails est cassé. Monit surveille en plus le journal d’envoi pour repérer les échecs de livraison.
À retenir : le silence n’est pas un signal. Une tâche doit signaler qu’elle a tourné, et l’alerte doit prouver qu’elle vous atteint encore.
📉 Un budget d’erreurs pour les journaux
Deux exporters ont écrit des erreurs pendant des jours sans qu’aucune métrique ne le montre. Une nouvelle alerte Loki compte les lignes d’erreur et d’avertissement par service et se déclenche au-delà de 100 par heure. Le bruit connu et inoffensif figure sur une liste d’exceptions, avec sa justification.
À retenir : un service qui se plaint sans arrêt est un constat, même si toutes ses métriques semblent bonnes.
🔍 Des sondes d’upload dans le journal d’accès – et ce qu’ont montré les deux premiers jours
Le 21 octobre, une faille critique dans le traitement des envois de fichiers (multipart/form-data) par PHP a été rendue publique : un envoi forgé pouvait amener PHP à exécuter le code de l’expéditeur. Des scanners l’ont essayée en moins d’une journée. Dans le journal d’accès, une telle sonde ressemblait à n’importe quel formulaire – juste POST /.
L’ingress enregistre désormais aussi le type de contenu et la taille de chaque requête. Cela suffit pour un motif simple : un envoi multipart de quelques kilo-octets vers une page qui n’accepte jamais d’envoi, comme la page d’accueil ou la page de connexion, est une sonde – pas un visiteur.
Les deux premiers jours du nouveau journal : des scanners ont envoyé de tels uploads aux trois serveurs, surtout depuis des adresses de grands hébergeurs cloud. L’un d’eux en a tiré 32 en une seule seconde, environ 6 Ko chacun, en changeant de nom de navigateur toutes les quelques requêtes pour passer pour un visiteur normal. Le contenu est un formulaire forgé, censé faire dérailler l’analyseur d’uploads. Si cela avait fonctionné, le serveur aurait exécuté le code de l’attaquant – en général un petit web shell, une porte dérobée qui accepte des commandes via HTTP.
Rien n’est passé. Chaque sonde a reçu un 400 (refusé), un 404 ou une redirection, et aucune n’a obtenu de réponse avec du contenu. Plusieurs expéditeurs étaient déjà bannis par fail2ban pour avoir sondé d’autres chemins interdits. Les envois normaux – clients de bureau Nextcloud, aperçus de documents, médias dans l’administration du blog – se distinguent nettement : autres chemins, autres types de contenu, utilisateurs connectés.
À retenir : on ne peut juger que ce que les journaux enregistrent. Deux champs de plus ont transformé « probablement une attaque » en « sûrement une sonde, sûrement refusée ».
🔧 Le reste
- Le blog passe à PHP 8.5.
- Limite mémoire de PHP-FPM sur le blog relevée de 1 Gio à 1,5 Gio – douze workers plus OPcache n’ont jamais tenu dans 1 Gio ; l’ancien commentaire supposait moitié moins de mémoire par worker. Une erreur de ma part, trouvée en mesurant.
- Mises à jour progressives (rolling updates) pour les pods applicatifs : le nouveau pod démarre avant que l’ancien ne s’arrête.
- Serveurs Nextcloud sur Redis 7, issu du flux de modules de la distribution.
- Journal d’accès de l’ingress avec le type de contenu et la taille de la requête – on distingue désormais les envois multipart suspects des formulaires normaux.
- Pressure Stall Information (PSI) activé au démarrage, pour que le panneau de pression affiche des données.
🧭 La suite : rien de nouveau – volontairement
Pour les semaines et les mois à venir, je n’ai prévu ni nouvelles fonctionnalités ni autres changements. L’installation fait ce qu’elle doit faire, et chaque nouveau composant apporterait de nouvelles sources de panne. Le temps va désormais à la compréhension de l’existant – relire la configuration avec un œil neuf, mesurer plutôt que deviner – et à la documentation : les deep dives, les guides d’exploitation et les leçons dans les commentaires du code.
La maintenance continue comme d’habitude : mises à jour chaque lundi, certificats, correctifs de sécurité. Des corrections de bugs, oui ; de nouvelles fonctionnalités seulement en cas de vrai besoin.
À retenir : une installation que l’on comprend vaut plus qu’une fonctionnalité de plus. La stabilité aussi est une décision.
🎯 Les leçons
- Tester l’effet, pas la configuration.
- Chaque tâche périodique a besoin d’un signal de vie ; le silence ne veut pas dire « tout va bien ».
- Prouver régulièrement le chemin d’alerte, avec une alerte qui se déclenche toujours.
- Suivre les symptômes – une alerte CPU d’apparence anodine a mené à des téléchargements cassés.
- Les valeurs par défaut sont des décisions prises par d’autres ; il faut les confronter à ses propres ordres de grandeur.
La liste complète des changements se trouve dans le message du tag v3.6.0.





