<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>#homelab — Blog d'Ange Bonkoski</title><link>https://journal.ange-bonkoski.fr/tags/homelab/</link><description>Journal de mon homelab et write-ups de labs de cybersécurité.</description><language>fr</language><copyright>Ange Bonkoski, licence CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/deed.fr)</copyright><lastBuildDate>Mon, 19 Oct 2026 11:00:00 +0200</lastBuildDate><atom:link href="https://journal.ange-bonkoski.fr/tags/homelab/index.xml" rel="self" type="application/rss+xml"/><item><title>Quatre blocages en une journée : diagnostiquer couche par couche</title><link>https://journal.ange-bonkoski.fr/journal/guacamole-couche-par-couche/</link><pubDate>Mon, 19 Oct 2026 11:00:00 +0200</pubDate><guid>https://journal.ange-bonkoski.fr/journal/guacamole-couche-par-couche/</guid><category>homelab</category><category>guacamole</category><category>ssh</category><category>vnc</category><category>diagnostic</category><description>&lt;p&gt;Je voulais pouvoir administrer mon serveur et prendre la main sur mon PC&#10;fixe depuis &lt;strong&gt;n&amp;rsquo;importe quel navigateur&lt;/strong&gt;, même sur un téléphone, sans rien&#10;installer. C&amp;rsquo;est le rôle d&amp;rsquo;&lt;strong&gt;Apache Guacamole&lt;/strong&gt; : un bastion d&amp;rsquo;accès web.&lt;/p&gt;&#10;&lt;p&gt;L&amp;rsquo;installation m&amp;rsquo;a pris une journée, et j&amp;rsquo;ai buté quatre fois. Ce n&amp;rsquo;est pas&#10;le nombre de blocages qui m&amp;rsquo;a appris le plus, c&amp;rsquo;est la méthode qui a permis&#10;de tous les résoudre.&lt;/p&gt;&#10;&lt;h2 id="comment-guacamole-fonctionne"&gt;Comment Guacamole fonctionne&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Navigateur ──HTTPS──&amp;gt; Guacamole (interface web)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; guacd ──SSH──&amp;gt; serveur&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─VNC──&amp;gt; PC fixe&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le navigateur ne parle qu&amp;rsquo;en HTTPS avec l&amp;rsquo;interface web. C&amp;rsquo;est &lt;code&gt;guacd&lt;/code&gt;, un&#10;petit moteur qui tourne sur le serveur, qui ouvre réellement les connexions&#10;SSH ou VNC vers les machines cibles, puis renvoie l&amp;rsquo;image au navigateur.&#10;Une base PostgreSQL garde les comptes et les connexions. Les trois tournent&#10;dans des conteneurs Docker, et aucun ne publie de port : on y accède&#10;seulement par mon réseau privé Tailscale, avec double authentification.&lt;/p&gt;&#10;&lt;h2 id="blocage-n1--le-certificat-qui-refusait-de-se-faire"&gt;Blocage n°1 : le certificat qui refusait de se faire&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;Symptôme :&lt;/strong&gt; « Internal Error » en enregistrant le nom de domaine dans le&#10;reverse proxy.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Le journal :&lt;/strong&gt; &lt;code&gt;docker logs&lt;/code&gt; du reverse proxy montrait la commande de&#10;Let&amp;rsquo;s Encrypt avec &lt;code&gt;--preferred-challenges http&lt;/code&gt;, puis&#10;&lt;code&gt;Some challenges have failed&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;La cause :&lt;/strong&gt; j&amp;rsquo;avais oublié de cocher « Use a DNS Challenge ». Le défi&#10;HTTP demande à Let&amp;rsquo;s Encrypt de venir chercher un fichier sur mon serveur&#10;depuis Internet… alors qu&amp;rsquo;aucun port n&amp;rsquo;est ouvert. Il ne pouvait&#10;&lt;strong&gt;qu&amp;rsquo;échouer&lt;/strong&gt;. Avec le défi DNS, le certificat est arrivé en une minute.&lt;/p&gt;&#10;&lt;p&gt;Cet échec avait un bon côté : il prouvait que mon serveur est vraiment&#10;injoignable depuis Internet.&lt;/p&gt;&#10;&lt;h2 id="blocage-n2--la-clé-ssh--au-format-inconnu-"&gt;Blocage n°2 : la clé SSH « au format inconnu »&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;Symptôme :&lt;/strong&gt; la connexion SSH vers le serveur échoue.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Le journal, côté client&lt;/strong&gt; (&lt;code&gt;guacd&lt;/code&gt;) :&#10;&lt;code&gt;Unable to extract public key from private key file: Unsupported private key file format&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Le journal, côté serveur&lt;/strong&gt; (&lt;code&gt;sshd&lt;/code&gt;) : une connexion fermée avant&#10;authentification, puis une pénalité de 10 secondes pour cette adresse.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;La cause :&lt;/strong&gt; j&amp;rsquo;avais collé la clé privée &lt;strong&gt;sans&lt;/strong&gt; ses lignes&#10;&lt;code&gt;-----BEGIN …&lt;/code&gt; et &lt;code&gt;-----END …&lt;/code&gt;. Sans elles, impossible de reconnaître le&#10;format. Elles font partie de la clé.&lt;/p&gt;&#10;&lt;p&gt;Le journal du serveur m&amp;rsquo;a aussi appris quelque chose : les versions&#10;récentes de &lt;code&gt;sshd&lt;/code&gt; &lt;strong&gt;pénalisent&lt;/strong&gt; une adresse qui se connecte sans&#10;s&amp;rsquo;authentifier. Pendant le diagnostic, les reconnexions automatiques de&#10;Guacamole aggravaient la situation. J&amp;rsquo;ai dû les couper.&lt;/p&gt;&#10;&lt;h2 id="blocage-n3--le-bureau-à-distance-qui-nexistait-pas"&gt;Blocage n°3 : le Bureau à distance… qui n&amp;rsquo;existait pas&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;Symptôme :&lt;/strong&gt; impossible de joindre mon PC fixe en RDP.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;La vérification :&lt;/strong&gt; « À propos de Windows » → &lt;strong&gt;Windows 11 Famille&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;La cause :&lt;/strong&gt; l&amp;rsquo;édition Famille ne peut pas &lt;strong&gt;recevoir&lt;/strong&gt; de connexion&#10;Bureau à distance, c&amp;rsquo;est réservé aux éditions Pro. Plutôt que de payer une&#10;licence, je suis passé à &lt;strong&gt;VNC&lt;/strong&gt; avec TightVNC (gratuit), verrouillé par&#10;deux protections indépendantes : TightVNC n&amp;rsquo;accepte que l&amp;rsquo;adresse du&#10;serveur, et le pare-feu Windows aussi.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-attention" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/&gt;&lt;path d="M12 9v4"/&gt;&lt;path d="M12 17h.01"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;L&amp;#39;installateur qui ouvre une porte sans le dire&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;En vérifiant le pare-feu après coup, j&amp;rsquo;ai trouvé une règle créée par&#10;l&amp;rsquo;installateur de TightVNC : elle autorisait &lt;strong&gt;tout le monde&lt;/strong&gt; à se&#10;connecter. Je l&amp;rsquo;ai désactivée. Toujours relire le pare-feu après avoir&#10;installé un logiciel serveur.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="blocage-n4---unable-to-connect-to-vnc-server-"&gt;Blocage n°4 : « Unable to connect to VNC server »&lt;/h2&gt;&#10;&lt;p&gt;C&amp;rsquo;est le blocage le plus instructif, parce que je l&amp;rsquo;ai résolu en&#10;remontant les couches une par une :&lt;/p&gt;&#10;&#10;&lt;div class="tableau" role="region" aria-label="Tableau" tabindex="0"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th class="aligne-left"&gt;Couche&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Test&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Résultat&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Réseau (TCP)&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;le port 5900 du PC répond-il depuis le serveur ?&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;oui&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Service&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;le PC renvoie-t-il une bannière VNC (&lt;code&gt;RFB 003.008&lt;/code&gt;) ?&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;oui, même depuis le conteneur de &lt;code&gt;guacd&lt;/code&gt;&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Authentification&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;que dit le journal de TightVNC ?&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;&lt;code&gt;Authentication failed&lt;/code&gt;&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Le réseau et le service étaient bons. Le problème était à la dernière&#10;couche : le mot de passe VNC enregistré dans Guacamole et celui de&#10;TightVNC &lt;strong&gt;n&amp;rsquo;étaient pas les mêmes&lt;/strong&gt;. Je les ai redéfinis des deux côtés à&#10;partir de mon gestionnaire de mots de passe, et tout a fonctionné.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-lecon" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M9 18h6"/&gt;&lt;path d="M10 22h4"/&gt;&lt;path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Un port ouvert ne prouve qu&amp;#39;une chose&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;« Le port répond » valide la couche réseau, et rien d&amp;rsquo;autre. Il faut&#10;tester chaque couche : la connexion TCP, puis le service (sa bannière),&#10;puis l&amp;rsquo;authentification.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="le-détail-qui-ma-fait-comprendre-la-nat-de-docker"&gt;Le détail qui m&amp;rsquo;a fait comprendre la NAT de Docker&lt;/h2&gt;&#10;&lt;p&gt;En configurant les deux connexions, j&amp;rsquo;ai remarqué que les cibles ne&#10;voyaient pas arriver la même adresse :&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;vers le serveur lui-même&lt;/strong&gt;, &lt;code&gt;sshd&lt;/code&gt; voyait l&amp;rsquo;adresse &lt;strong&gt;interne&lt;/strong&gt; du&#10;conteneur &lt;code&gt;guacd&lt;/code&gt;. J&amp;rsquo;ai donc limité la clé SSH de Guacamole aux réseaux&#10;internes de Docker (option &lt;code&gt;from=&lt;/code&gt; dans &lt;code&gt;authorized_keys&lt;/code&gt;) ;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;vers le PC&lt;/strong&gt;, TightVNC voyait l&amp;rsquo;adresse &lt;strong&gt;du serveur&lt;/strong&gt; : en sortant vers&#10;le réseau local, Docker remplace l&amp;rsquo;adresse du conteneur par celle de&#10;l&amp;rsquo;hôte (c&amp;rsquo;est de la NAT). La règle de TightVNC autorise donc le serveur.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Comprendre ce comportement était indispensable pour écrire des règles&#10;d&amp;rsquo;accès qui marchent, et qui restent strictes.&lt;/p&gt;&#10;&lt;h2 id="ce-que-jen-retiens"&gt;Ce que j&amp;rsquo;en retiens&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Lire les journaux des deux côtés.&lt;/strong&gt; Le client dit ce qu&amp;rsquo;il a tenté ; le&#10;serveur dit pourquoi il a refusé. Pour SSH comme pour VNC, c&amp;rsquo;est le&#10;serveur qui a donné la cause.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Tester couche par couche&lt;/strong&gt;, du réseau à l&amp;rsquo;authentification, au lieu de&#10;tout changer en même temps.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Un bloc de clé se copie en entier&lt;/strong&gt;, lignes BEGIN et END comprises.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Les outils de diagnostic sont temporaires&lt;/strong&gt; : niveau de journalisation&#10;maximal, conteneurs de test… tout a été retiré une fois la cause trouvée.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>En installant un simple partage de fichiers, j'ai trouvé trois portes de côté</title><link>https://journal.ange-bonkoski.fr/journal/trois-portes-de-cote/</link><pubDate>Mon, 19 Oct 2026 10:00:00 +0200</pubDate><guid>https://journal.ange-bonkoski.fr/journal/trois-portes-de-cote/</guid><category>homelab</category><category>smb</category><category>zimaos</category><category>sécurité</category><category>moindre-privilège</category><description>&lt;p&gt;La veille, j&amp;rsquo;avais fini de durcir l&amp;rsquo;accès SSH à mon serveur : connexion par&#10;clé uniquement, mots de passe interdits, un seul compte autorisé. J&amp;rsquo;en&#10;étais assez fier.&lt;/p&gt;&#10;&lt;p&gt;Le lendemain, je voulais quelque chose de beaucoup plus banal : regarder&#10;mes vidéos depuis le Mac et l&amp;rsquo;iPhone, via un partage de fichiers SMB. En&#10;le configurant proprement, je suis tombé sur &lt;strong&gt;trois portes&lt;/strong&gt; que je&#10;n&amp;rsquo;avais jamais notées nulle part. L&amp;rsquo;une d&amp;rsquo;elles rendait mon travail de la&#10;veille inutile.&lt;/p&gt;&#10;&lt;h2 id="porte-n1--le-partage--admin--qui-voyait-tout"&gt;Porte n°1 : le partage « admin » qui voyait tout&lt;/h2&gt;&#10;&lt;p&gt;Mon serveur tourne sous ZimaOS. Son interface crée automatiquement un&#10;partage SMB pour le compte d&amp;rsquo;administration. Je ne m&amp;rsquo;en étais jamais&#10;soucié : je l&amp;rsquo;utilisais pour transférer des fichiers depuis mon PC.&lt;/p&gt;&#10;&lt;p&gt;En le regardant de près, j&amp;rsquo;ai découvert qu&amp;rsquo;il donnait accès &lt;strong&gt;à tous les&#10;disques, en écriture&lt;/strong&gt;, y compris la partition qui contient les données des&#10;conteneurs, les fichiers de configuration… et le fichier &lt;code&gt;authorized_keys&lt;/code&gt;,&#10;celui qui liste les clés SSH autorisées.&lt;/p&gt;&#10;&lt;p&gt;J&amp;rsquo;ai vérifié en le listant avec &lt;code&gt;smbclient&lt;/code&gt; et le seul mot de passe du&#10;compte d&amp;rsquo;administration. Il était bien là, lisible et modifiable.&lt;/p&gt;&#10;&lt;p&gt;Autrement dit : quelqu&amp;rsquo;un qui connaissait ce mot de passe pouvait&#10;&lt;strong&gt;ajouter sa propre clé&lt;/strong&gt; par SMB, puis se connecter en SSH. Mon « SSH par&#10;clé uniquement » se contournait par la porte d&amp;rsquo;à côté.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-lecon" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M9 18h6"/&gt;&lt;path d="M10 22h4"/&gt;&lt;path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Leçon&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Un durcissement ne vaut que si &lt;strong&gt;toutes&lt;/strong&gt; les portes vers la même&#10;ressource sont fermées. Protéger SSH ne sert à rien si un autre service&#10;permet de modifier les clés de SSH.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="porte-n2--les-lecteurs-réseau-toujours-branchés"&gt;Porte n°2 : les lecteurs réseau toujours branchés&lt;/h2&gt;&#10;&lt;p&gt;Sur mon PC Windows, deux lecteurs réseau étaient connectés en permanence&#10;avec ce même compte d&amp;rsquo;administration : l&amp;rsquo;un vers le disque externe, l&amp;rsquo;autre&#10;vers la partition de données du serveur.&lt;/p&gt;&#10;&lt;p&gt;C&amp;rsquo;est exactement le scénario qu&amp;rsquo;exploitent les &lt;strong&gt;rançongiciels&lt;/strong&gt; : ils&#10;chiffrent tout ce qu&amp;rsquo;ils trouvent, y compris les lecteurs réseau. Un&#10;simple fichier piégé ouvert sur le PC aurait pu chiffrer le serveur, et&#10;avec lui… les données de mes sauvegardes.&lt;/p&gt;&#10;&lt;h2 id="porte-n3--un-deuxième-accès-distant-que-je-navais-pas-choisi"&gt;Porte n°3 : un deuxième accès distant que je n&amp;rsquo;avais pas choisi&lt;/h2&gt;&#10;&lt;p&gt;En nettoyant les identifiants mémorisés sur mon PC, j&amp;rsquo;en ai trouvé un pour&#10;une adresse que je ne connaissais pas. En remontant la piste : &lt;strong&gt;ZeroTier&lt;/strong&gt;,&#10;un réseau privé virtuel installé et activé par ZimaOS pour son application&#10;« Zima Client ».&lt;/p&gt;&#10;&lt;p&gt;J&amp;rsquo;utilisais déjà Tailscale comme unique accès distant, volontairement.&#10;ZeroTier était un &lt;strong&gt;deuxième&lt;/strong&gt; chemin vers le serveur, géré par l&amp;rsquo;éditeur,&#10;que je n&amp;rsquo;avais jamais décidé d&amp;rsquo;ouvrir.&lt;/p&gt;&#10;&lt;h2 id="ce-que-jai-fait"&gt;Ce que j&amp;rsquo;ai fait&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;Des comptes dédiés, avec le minimum de droits.&lt;/strong&gt; Au lieu du compte&#10;d&amp;rsquo;administration, deux comptes de partage, sans accès SSH ni shell :&lt;/p&gt;&#10;&#10;&lt;div class="tableau" role="region" aria-label="Tableau" tabindex="0"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th class="aligne-left"&gt;Compte&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Accès&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Usage&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Lecture&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;un seul dossier (les vidéos), &lt;strong&gt;lecture seule&lt;/strong&gt;&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;mémorisé sur le PC, le Mac et l&amp;rsquo;iPhone&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Dépôt&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;le dossier de sauvegarde, lecture-écriture&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;connecté &lt;strong&gt;seulement pendant un transfert&lt;/strong&gt;, mot de passe jamais mémorisé&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Le compte de lecture peut rester branché en permanence : un rançongiciel&#10;ne peut rien chiffrer avec. Le compte de dépôt, lui, n&amp;rsquo;existe sur le PC que&#10;quelques minutes à la fois.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Désactiver le compte SMB d&amp;rsquo;administration.&lt;/strong&gt; Une commande suffit :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smbpasswd -d admin &lt;span class="c1"&gt;# -d : désactive le compte Samba, sans le supprimer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mais ZimaOS &lt;strong&gt;le réactive à chaque redémarrage&lt;/strong&gt;. J&amp;rsquo;ai donc écrit un petit&#10;script, lancé par un timer systemd 3 minutes après le démarrage puis toutes&#10;les 10 minutes. Il redésactive le compte si besoin, vérifie que c&amp;rsquo;est bien&#10;fait, et me prévient sur Discord quand il a dû intervenir.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-attention" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/&gt;&lt;path d="M12 9v4"/&gt;&lt;path d="M12 17h.01"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Les systèmes qui se « réparent » tout seuls&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Sur un système qui régénère sa configuration au démarrage, une correction&#10;faite à la main peut disparaître sans prévenir. Il faut soit la rendre&#10;persistante, soit la réappliquer automatiquement, et surtout le&#10;&lt;strong&gt;vérifier après un redémarrage&lt;/strong&gt;.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;p&gt;&lt;strong&gt;Débrancher les lecteurs du PC&lt;/strong&gt;, et ne plus jamais connecter le compte&#10;d&amp;rsquo;administration depuis un poste.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Retirer ZeroTier&lt;/strong&gt; : le serveur a quitté le réseau, et le service a été&#10;masqué pour qu&amp;rsquo;il ne puisse plus redémarrer, même par erreur.&lt;/p&gt;&#10;&lt;h2 id="vérifier-avec-des-tests-écrits"&gt;Vérifier, avec des tests écrits&lt;/h2&gt;&#10;&lt;p&gt;J&amp;rsquo;ai ensuite déroulé une série de tests, notés un par un : chaque compte&#10;voit-il seulement ce qu&amp;rsquo;il doit voir ? Le compte de lecture peut-il écrire ?&#10;Les partages sont-ils joignables depuis Internet sans Tailscale ? Le compte&#10;d&amp;rsquo;administration est-il bien désactivé après un redémarrage ? Tous les&#10;tests sont passés, depuis le PC, le Mac et l&amp;rsquo;iPhone.&lt;/p&gt;&#10;&lt;h2 id="ce-que-jen-retiens"&gt;Ce que j&amp;rsquo;en retiens&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Inventorier les accès, pas seulement les sécuriser.&lt;/strong&gt; On ne peut pas&#10;fermer une porte qu&amp;rsquo;on ne sait pas exister.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Le moindre privilège, concrètement :&lt;/strong&gt; un compte par usage, et le&#10;minimum de droits pour cet usage.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Se méfier de ce qu&amp;rsquo;une plateforme active « pour vous ».&lt;/strong&gt; Une&#10;fonctionnalité pratique est aussi une surface d&amp;rsquo;attaque.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Penser comme un attaquant :&lt;/strong&gt; « si j&amp;rsquo;avais ce mot de passe, jusqu&amp;rsquo;où&#10;irais-je ? » C&amp;rsquo;est cette question qui a fait apparaître la porte n°1.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Mon coffre de mots de passe ne répondait plus, et le réseau n'y était pour rien</title><link>https://journal.ange-bonkoski.fr/journal/le-reseau-n-y-etait-pour-rien/</link><pubDate>Mon, 19 Oct 2026 09:00:00 +0200</pubDate><guid>https://journal.ange-bonkoski.fr/journal/le-reseau-n-y-etait-pour-rien/</guid><category>homelab</category><category>vaultwarden</category><category>docker</category><category>diagnostic</category><description>&lt;p&gt;Le 20 septembre, mon gestionnaire de mots de passe auto-hébergé a&#10;cessé de fonctionner… à moitié. Le coffre s&amp;rsquo;ouvrait parfaitement dans le&#10;navigateur. Mais l&amp;rsquo;extension Firefox affichait une erreur obscure, et&#10;l&amp;rsquo;application iPhone refusait de se connecter.&lt;/p&gt;&#10;&lt;p&gt;J&amp;rsquo;ai passé des heures à chercher dans la mauvaise direction. Cet article&#10;raconte comment j&amp;rsquo;en suis sorti, et surtout la petite expérience qui a&#10;tout débloqué.&lt;/p&gt;&#10;&lt;h2 id="le-contexte"&gt;Le contexte&lt;/h2&gt;&#10;&lt;p&gt;J&amp;rsquo;héberge &lt;strong&gt;Vaultwarden&lt;/strong&gt; sur mon serveur maison. C&amp;rsquo;est une réécriture&#10;légère du serveur de &lt;strong&gt;Bitwarden&lt;/strong&gt; : on garde les applications officielles&#10;de Bitwarden (extension, application mobile), mais elles parlent à mon&#10;serveur plutôt qu&amp;rsquo;à celui de l&amp;rsquo;éditeur.&lt;/p&gt;&#10;&lt;p&gt;À l&amp;rsquo;époque, le trafic passait par Cloudflare, puis par un reverse proxy,&#10;avant d&amp;rsquo;arriver au conteneur.&lt;/p&gt;&#10;&lt;h2 id="le-symptôme"&gt;Le symptôme&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Le coffre web&lt;/strong&gt; : fonctionne.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;L&amp;rsquo;extension Firefox&lt;/strong&gt; : &lt;code&gt;KDF config response does not contain a valid KDF type&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;L&amp;rsquo;application iOS&lt;/strong&gt; : « Nous ne sommes pas en mesure de traiter votre demande ».&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Le KDF (&lt;em&gt;key derivation function&lt;/em&gt;) est la fonction qui transforme le mot de&#10;passe maître en clé de chiffrement. Le client demande au serveur quels&#10;paramètres utiliser, puis fait le calcul lui-même. L&amp;rsquo;erreur disait donc :&#10;« la réponse du serveur ne ressemble pas à ce que j&amp;rsquo;attends ».&lt;/p&gt;&#10;&lt;h2 id="pourquoi-jai-accusé-le-réseau"&gt;Pourquoi j&amp;rsquo;ai accusé le réseau&lt;/h2&gt;&#10;&lt;p&gt;Ma première intuition : quelque chose entre le client et le serveur&#10;abîmait la réponse. C&amp;rsquo;était plausible, car proxys et CDN modifient parfois&#10;le trafic au passage. J&amp;rsquo;ai donc testé, une par une :&lt;/p&gt;&#10;&#10;&lt;div class="tableau" role="region" aria-label="Tableau" tabindex="0"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th class="aligne-left"&gt;Piste testée&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Résultat&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Désactiver les protections anti-robots de Cloudflare&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Aucun effet&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Règle de pare-feu applicatif pour laisser tout passer&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Aucun effet&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Purger le cache Cloudflare&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Aucun effet&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Désactiver HTTP/3 et le 0-RTT&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Aucun effet&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Vérifier la compression de la réponse&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;JSON propre une fois décompressé&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Corriger l&amp;rsquo;adresse publique déclarée dans la configuration&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Vrai défaut, mais pas suffisant&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Chaque test prenait du temps, et aucun ne changeait rien.&lt;/p&gt;&#10;&lt;h2 id="le-friend-test"&gt;Le &lt;em&gt;friend test&lt;/em&gt;&lt;/h2&gt;&#10;&lt;p&gt;J&amp;rsquo;ai fini par emprunter le téléphone d&amp;rsquo;un proche. Il n&amp;rsquo;avait jamais été&#10;connecté à mon réseau, ni à mon compte iCloud, ni à mon Firefox. J&amp;rsquo;y ai&#10;installé l&amp;rsquo;application Bitwarden, je l&amp;rsquo;ai pointée vers mon serveur…&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Même erreur, exactement.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Ce test a éliminé d&amp;rsquo;un coup toutes mes hypothèses réseau. Un problème&#10;propre à mon infrastructure, à mon cache ou à mes appareils n&amp;rsquo;aurait pas&#10;touché un téléphone neuf. Le problème venait de ce que &lt;strong&gt;tous&lt;/strong&gt; les clients&#10;avaient en commun : la version de l&amp;rsquo;application.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-lecon" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M9 18h6"/&gt;&lt;path d="M10 22h4"/&gt;&lt;path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Le friend test&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Quand tout semble suspect, reproduisez le problème sur un appareil qui ne&#10;partage &lt;strong&gt;rien&lt;/strong&gt; avec les vôtres. S&amp;rsquo;il plante pareil, ce n&amp;rsquo;est ni votre&#10;réseau, ni votre configuration locale.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="la-vraie-cause--un-contrat-de-version-rompu"&gt;La vraie cause : un contrat de version rompu&lt;/h2&gt;&#10;&lt;p&gt;Pourquoi le coffre web, lui, fonctionnait-il ? Parce que Vaultwarden sert&#10;&lt;strong&gt;sa propre&lt;/strong&gt; interface web, compilée avec lui, à la même version. Elle&#10;comprend forcément ses réponses. C&amp;rsquo;était le pire témoin possible.&lt;/p&gt;&#10;&lt;p&gt;L&amp;rsquo;extension et l&amp;rsquo;application, elles, sont publiées par Bitwarden et mises à&#10;jour automatiquement par les magasins d&amp;rsquo;applications, sans aucun lien avec&#10;mon serveur. Bitwarden avait fait évoluer la structure de la réponse KDF.&#10;Les clients avaient adopté le nouveau format ; mon serveur ne le parlait&#10;pas encore. Il fallait une version plus récente de Vaultwarden.&lt;/p&gt;&#10;&lt;h2 id="pourquoi-la-mise-à-jour-na-pas-marché-du-premier-coup"&gt;Pourquoi la mise à jour n&amp;rsquo;a pas marché du premier coup&lt;/h2&gt;&#10;&lt;p&gt;J&amp;rsquo;ai lancé la mise à jour du conteneur… et rien n&amp;rsquo;a changé. En relisant&#10;mon fichier Compose, j&amp;rsquo;ai trouvé ceci :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vaultwarden/server:1.36.0@sha256:&amp;lt;empreinte&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker peut désigner une image de deux façons :&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;par une &lt;strong&gt;étiquette&lt;/strong&gt; (&lt;code&gt;1.36.0&lt;/code&gt;, &lt;code&gt;latest&lt;/code&gt;) : un nom qui peut pointer vers&#10;une autre image demain ;&lt;/li&gt;&#10;&lt;li&gt;par une &lt;strong&gt;empreinte&lt;/strong&gt; (&lt;code&gt;sha256:…&lt;/code&gt;) : l&amp;rsquo;identifiant exact d&amp;rsquo;une image,&#10;qui ne change jamais.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Quand les deux sont présentes, &lt;strong&gt;l&amp;rsquo;empreinte l&amp;rsquo;emporte&lt;/strong&gt;. J&amp;rsquo;avais beau&#10;télécharger de nouvelles versions, Docker relançait toujours la même image&#10;figée. Une fois l&amp;rsquo;empreinte retirée et une version récente demandée,&#10;l&amp;rsquo;extension et l&amp;rsquo;application se sont reconnectées immédiatement.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-attention" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/&gt;&lt;path d="M12 9v4"/&gt;&lt;path d="M12 17h.01"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Épingler n&amp;#39;est pas une erreur, l&amp;#39;oublier si&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Figer une image par son empreinte est une bonne pratique de sécurité : on&#10;sait exactement ce qui tourne. Le piège, c&amp;rsquo;est de l&amp;rsquo;avoir fait sans s&amp;rsquo;en&#10;souvenir. Depuis, chaque service a une politique d&amp;rsquo;image écrite : figé (et&#10;mis à jour à la main) ou suivi automatiquement.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="ce-que-jen-retiens"&gt;Ce que j&amp;rsquo;en retiens&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Vérifier la compatibilité client/serveur avant de chercher dans le&#10;réseau.&lt;/strong&gt; Quand des clients mis à jour automatiquement cassent, la version&#10;est le premier suspect.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Choisir un bon témoin.&lt;/strong&gt; Un client livré avec le serveur ne prouve rien&#10;sur les autres.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Lire le fichier réel avant de mettre à jour.&lt;/strong&gt; Ce que je croyais avoir&#10;configuré et ce qui était écrit n&amp;rsquo;étaient pas la même chose.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Changer une seule chose à la fois.&lt;/strong&gt; C&amp;rsquo;est ce qui m&amp;rsquo;a permis de repérer&#10;le seul vrai défaut parmi mes essais.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>CrowdSec, et le test qui ne prouvait rien</title><link>https://journal.ange-bonkoski.fr/journal/crowdsec-le-test-qui-ne-prouvait-rien/</link><pubDate>Sun, 18 Oct 2026 12:00:00 +0200</pubDate><guid>https://journal.ange-bonkoski.fr/journal/crowdsec-le-test-qui-ne-prouvait-rien/</guid><category>homelab</category><category>crowdsec</category><category>détection</category><category>docker</category><category>discord</category><description>&lt;p&gt;J&amp;rsquo;ai installé &lt;strong&gt;CrowdSec&lt;/strong&gt; sur mon homelab pour une raison simple : je&#10;voulais savoir si quelqu&amp;rsquo;un s&amp;rsquo;en prenait à mon serveur. L&amp;rsquo;installation&#10;s&amp;rsquo;est bien passée. Les alertes, elles, n&amp;rsquo;arrivaient pas sur Discord. Et la&#10;commande censée les tester me répondait… rien. Ni succès, ni erreur.&lt;/p&gt;&#10;&lt;p&gt;Cet article raconte comment j&amp;rsquo;ai trouvé la panne, et pourquoi la leçon&#10;dépasse largement CrowdSec.&lt;/p&gt;&#10;&lt;h2 id="crowdsec-en-deux-minutes"&gt;CrowdSec en deux minutes&lt;/h2&gt;&#10;&lt;p&gt;CrowdSec est un outil de détection d&amp;rsquo;intrusion. Il fonctionne comme une&#10;chaîne :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journaux → analyseurs → scénarios → alerte → notification&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(SSH, web) (lisent (reconnaissent (décision) (Discord)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; chaque ligne) une attaque)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;Il &lt;strong&gt;lit les journaux&lt;/strong&gt; du serveur : ici, les connexions SSH et les&#10;accès au reverse proxy.&lt;/li&gt;&#10;&lt;li&gt;Des &lt;strong&gt;analyseurs&lt;/strong&gt; découpent chaque ligne (adresse IP, utilisateur,&#10;résultat).&lt;/li&gt;&#10;&lt;li&gt;Des &lt;strong&gt;scénarios&lt;/strong&gt; reconnaissent un comportement suspect, par exemple&#10;une rafale d&amp;rsquo;échecs de connexion SSH depuis la même adresse en&#10;quelques secondes : une attaque par force brute.&lt;/li&gt;&#10;&lt;li&gt;Une &lt;strong&gt;alerte&lt;/strong&gt; est créée, et un &lt;strong&gt;plugin&lt;/strong&gt; l&amp;rsquo;envoie ailleurs, ici vers&#10;un salon Discord privé.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;CrowdSec peut aussi &lt;strong&gt;bloquer&lt;/strong&gt; les adresses fautives, grâce à un composant&#10;séparé (un &lt;em&gt;bouncer&lt;/em&gt;). Je ne l&amp;rsquo;ai pas installé, volontairement : mon&#10;serveur n&amp;rsquo;a aucun port ouvert sur Internet, donc aucune attaque extérieure&#10;ne peut l&amp;rsquo;atteindre. Mon but était d&amp;rsquo;apprendre la chaîne de détection et de&#10;surveiller ce qui se passe, pas de risquer de me bloquer moi-même.&lt;/p&gt;&#10;&lt;h2 id="le-symptôme"&gt;Le symptôme&lt;/h2&gt;&#10;&lt;p&gt;CrowdSec propose une commande pour tester une notification :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cscli notifications &lt;span class="nb"&gt;test&lt;/span&gt; http_default&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Elle s&amp;rsquo;exécutait sans erreur. Sa sortie montrait le plugin qui démarre,&#10;puis qui s&amp;rsquo;arrête. Et sur Discord : rien. J&amp;rsquo;ai relancé plusieurs fois, en&#10;modifiant la configuration entre deux essais. Toujours rien.&lt;/p&gt;&#10;&lt;h2 id="séparer-les-couches"&gt;Séparer les couches&lt;/h2&gt;&#10;&lt;p&gt;Quand une chaîne de plusieurs maillons ne fonctionne pas, deviner ne sert à&#10;rien. J&amp;rsquo;ai testé chaque maillon &lt;strong&gt;seul&lt;/strong&gt;, en partant du bout.&lt;/p&gt;&#10;&lt;h3 id="maillon-1--discord-reçoit-il-quoi-que-ce-soit-"&gt;Maillon 1 : Discord reçoit-il quoi que ce soit ?&lt;/h3&gt;&#10;&lt;p&gt;Un webhook Discord est une simple adresse à laquelle on envoie un message.&#10;On peut donc le tester sans CrowdSec. Problème : l&amp;rsquo;image de CrowdSec ne&#10;contient pas &lt;code&gt;curl&lt;/code&gt;. Plutôt que d&amp;rsquo;installer quoi que ce soit, j&amp;rsquo;ai utilisé&#10;un &lt;strong&gt;conteneur jetable&lt;/strong&gt; qui ne contient que &lt;code&gt;curl&lt;/code&gt; et disparaît après&#10;usage :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --rm --env-file .env curlimages/curl &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sh -c &lt;span class="s1"&gt;&amp;#39;curl -s -o /dev/null -w &amp;#34;%{http_code}\n&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; -H &amp;#34;Content-Type: application/json&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; -d &amp;#34;{\&amp;#34;content\&amp;#34;:\&amp;#34;Test du webhook\&amp;#34;}&amp;#34; &amp;#34;$DISCORD_WEBHOOK&amp;#34;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Réponse : &lt;code&gt;204&lt;/code&gt;, et le message est apparu sur Discord. Le webhook&#10;fonctionnait. Le problème était donc &lt;strong&gt;en amont&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h3 id="maillon-2--crowdsec-lit-il-le-bon-fichier-"&gt;Maillon 2 : CrowdSec lit-il le bon fichier ?&lt;/h3&gt;&#10;&lt;p&gt;&lt;code&gt;cscli notifications list&lt;/code&gt; indiquait bien &lt;code&gt;http_default&lt;/code&gt; comme actif. Mais&#10;« actif » voulait seulement dire qu&amp;rsquo;&lt;strong&gt;un&lt;/strong&gt; fichier portait ce nom. En&#10;regardant le fichier réellement présent &lt;strong&gt;dans le conteneur&lt;/strong&gt;, sa date et&#10;sa taille, j&amp;rsquo;ai compris : c&amp;rsquo;était le fichier &lt;strong&gt;par défaut&lt;/strong&gt; livré avec&#10;l&amp;rsquo;image, pas le mien. Ma configuration n&amp;rsquo;avait jamais été chargée.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-lecon" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M9 18h6"/&gt;&lt;path d="M10 22h4"/&gt;&lt;path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;« Actif » n&amp;#39;est pas « chargé »&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Une commande qui liste une configuration ne prouve pas que c&amp;rsquo;est &lt;strong&gt;la&#10;vôtre&lt;/strong&gt;. Allez voir le fichier réellement utilisé par le programme : sa&#10;date de modification et sa taille disent la vérité.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h3 id="maillon-3--la-commande-de-test-teste-t-elle-vraiment-quelque-chose-"&gt;Maillon 3 : la commande de test teste-t-elle vraiment quelque chose ?&lt;/h3&gt;&#10;&lt;p&gt;En corrigeant le fichier, j&amp;rsquo;ai aussi compris pourquoi le test restait&#10;muet. La commande démarre le plugin, lui confie le message… et s&amp;rsquo;arrête&#10;avant que l&amp;rsquo;envoi ait eu le temps de se faire. Ma configuration ajoutait&#10;en plus un délai de regroupement de 60 secondes avant chaque envoi : le&#10;test ne pouvait &lt;strong&gt;jamais&lt;/strong&gt; aboutir. J&amp;rsquo;ai retiré ce délai, et j&amp;rsquo;ai cessé de&#10;me fier à cette commande.&lt;/p&gt;&#10;&lt;h2 id="la-vraie-preuve--une-vraie-alerte"&gt;La vraie preuve : une vraie alerte&lt;/h2&gt;&#10;&lt;p&gt;Pour prouver que toute la chaîne fonctionne, il faut un test qui la&#10;&lt;strong&gt;traverse&lt;/strong&gt; entièrement, comme le ferait une vraie attaque. J&amp;rsquo;ai donc&#10;créé une décision manuelle contre une adresse fictive :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cscli decisions add --ip 203.0.113.99 --reason &lt;span class="s2"&gt;&amp;#34;test de bout en bout&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;L&amp;rsquo;alerte est arrivée sur Discord en quelques secondes. Puis j&amp;rsquo;ai supprimé&#10;cette décision de test.&lt;/p&gt;&#10;&lt;p&gt;Pourquoi &lt;code&gt;203.0.113.99&lt;/code&gt; ? Parce que cette plage (&lt;code&gt;203.0.113.0/24&lt;/code&gt;) est&#10;&lt;strong&gt;réservée à la documentation&lt;/strong&gt; : elle n&amp;rsquo;appartient à personne. C&amp;rsquo;est une&#10;bonne habitude, dans un test comme dans un article, pour ne jamais viser&#10;l&amp;rsquo;adresse de quelqu&amp;rsquo;un par erreur.&lt;/p&gt;&#10;&lt;h2 id="le-piège-suivant--les-adresses-privées"&gt;Le piège suivant : les adresses privées&lt;/h2&gt;&#10;&lt;p&gt;J&amp;rsquo;ai voulu aller plus loin et simuler une vraie attaque par force brute&#10;SSH depuis mon propre PC. Rien ne s&amp;rsquo;est déclenché. Normal : par défaut,&#10;CrowdSec &lt;strong&gt;ignore&lt;/strong&gt; les adresses privées (le réseau local, Docker,&#10;Tailscale). Une attaque venant de l&amp;rsquo;intérieur passe donc sous ses radars.&lt;/p&gt;&#10;&lt;p&gt;Pour vérifier qu&amp;rsquo;un scénario reconnaît bien une ligne de journal, CrowdSec&#10;propose &lt;code&gt;cscli explain&lt;/code&gt;. On lui donne une fausse ligne avec une adresse de&#10;documentation, et il montre chaque étape : quel analyseur l&amp;rsquo;a lue, quels&#10;scénarios se sont activés.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cscli explain --type syslog &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --log &lt;span class="s2"&gt;&amp;#34;Oct 18 10:00:00 serveur sshd[1234]: Failed password for invalid user test from 203.0.113.5 port 4242 ssh2&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ce-que-jen-retiens"&gt;Ce que j&amp;rsquo;en retiens&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Un test qui ne dit rien ne prouve rien.&lt;/strong&gt; Ni succès ni erreur, ce&#10;n&amp;rsquo;est pas « ça marche ».&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Tester chaque maillon seul, en partant du bout.&lt;/strong&gt; Le webhook, puis le&#10;fichier, puis le plugin : chaque étape élimine une hypothèse.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Préférer une vraie alerte à une commande de test.&lt;/strong&gt; Elle emprunte le&#10;même chemin qu&amp;rsquo;une attaque réelle.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Connaître les angles morts de son outil.&lt;/strong&gt; Ignorer les adresses&#10;privées est un choix raisonnable, mais il faut le savoir.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Un secret peut fuiter par un message d&amp;rsquo;erreur.&lt;/strong&gt; Une erreur d&amp;rsquo;envoi&#10;peut afficher l&amp;rsquo;adresse complète du webhook, qui suffit à quiconque pour&#10;écrire dans mon salon Discord. Avant de partager un journal, je masque&#10;toujours ce genre d&amp;rsquo;information.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>La sauvegarde qui s'est évaporée</title><link>https://journal.ange-bonkoski.fr/journal/la-sauvegarde-qui-sest-evaporee/</link><pubDate>Sun, 18 Oct 2026 11:00:00 +0200</pubDate><guid>https://journal.ange-bonkoski.fr/journal/la-sauvegarde-qui-sest-evaporee/</guid><category>homelab</category><category>sauvegarde</category><category>systemd</category><category>zimaos</category><category>supervision</category><description>&lt;p&gt;Le 9 octobre, en cherchant où ajouter une nouvelle tâche planifiée sur mon&#10;serveur, j&amp;rsquo;ai tapé &lt;code&gt;crontab -l&lt;/code&gt;. La réponse était vide. Ma sauvegarde&#10;nocturne, celle qui protège mon coffre de mots de passe, n&amp;rsquo;existait plus.&lt;/p&gt;&#10;&lt;p&gt;Elle ne s&amp;rsquo;était pas lancée la nuit précédente. Et aucune de mes alertes&#10;n&amp;rsquo;avait sonné.&lt;/p&gt;&#10;&lt;h2 id="le-dispositif-de-sauvegarde"&gt;Le dispositif de sauvegarde&lt;/h2&gt;&#10;&lt;p&gt;Chaque nuit à 3 h 30, un script sauvegarde les données importantes du&#10;serveur avec &lt;strong&gt;restic&lt;/strong&gt;, un outil qui produit des sauvegardes chiffrées,&#10;dédupliquées et versionnées. Le script :&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;fait une copie cohérente de la base de données du coffre, sans&#10;l&amp;rsquo;arrêter ;&lt;/li&gt;&#10;&lt;li&gt;l&amp;rsquo;envoie dans le dépôt restic, sur un disque séparé ;&lt;/li&gt;&#10;&lt;li&gt;supprime les anciennes versions selon une règle de rétention ;&lt;/li&gt;&#10;&lt;li&gt;vérifie un échantillon des données ;&lt;/li&gt;&#10;&lt;li&gt;signale « tout va bien » à ma supervision (Uptime Kuma), &lt;strong&gt;seulement si&#10;toutes les étapes ont réussi&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;Uptime Kuma attend ce signal. S&amp;rsquo;il ne reçoit rien pendant 26 heures, il&#10;m&amp;rsquo;envoie une alerte sur Discord. Sur le papier, une sauvegarde manquée ne&#10;pouvait donc pas passer inaperçue.&lt;/p&gt;&#10;&lt;h2 id="la-chronologie"&gt;La chronologie&lt;/h2&gt;&#10;&#10;&lt;div class="tableau" role="region" aria-label="Tableau" tabindex="0"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th class="aligne-left"&gt;Moment&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Ce qui s&amp;rsquo;est passé&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;8 oct., 3 h 30&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Dernière sauvegarde réussie.&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;8 oct., 17 h 40&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Je redémarre le serveur pour valider un changement de configuration SSH, sans aucun rapport avec les sauvegardes.&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;9 oct., 3 h 30&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Aucune sauvegarde. Aucun message.&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;9 oct., après-midi&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Plusieurs redémarrages pour d&amp;rsquo;autres travaux. Uptime Kuma affiche toujours « en ligne ».&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;9 oct., 17 h 40&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;Je découvre par hasard que la tâche planifiée a disparu.&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;h2 id="première-énigme--où-est-passée-la-tâche-"&gt;Première énigme : où est passée la tâche ?&lt;/h2&gt;&#10;&lt;p&gt;Mon serveur tourne sous &lt;strong&gt;ZimaOS&lt;/strong&gt;, un système conçu pour faire tourner des&#10;conteneurs. Pour être robuste, il ne ressemble pas à une distribution&#10;Linux classique :&lt;/p&gt;&#10;&#10;&lt;div class="tableau" role="region" aria-label="Tableau" tabindex="0"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th class="aligne-left"&gt;Zone&lt;/th&gt;&#10; &lt;th class="aligne-left"&gt;Comportement&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;&lt;code&gt;/&lt;/code&gt; (le système)&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;en lecture seule&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;&lt;code&gt;/etc&lt;/code&gt; (la configuration)&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;modifiable et conservée&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;&lt;code&gt;/var&lt;/code&gt;&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;&lt;strong&gt;en mémoire vive (tmpfs) : vidée à chaque démarrage&lt;/strong&gt;&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;la partition de données&lt;/td&gt;&#10; &lt;td class="aligne-left"&gt;modifiable et conservée&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;Or, quand on crée une tâche avec &lt;code&gt;crontab -e&lt;/code&gt;, cron l&amp;rsquo;enregistre dans&#10;&lt;code&gt;/var/spool/cron/&lt;/code&gt;. Sur ZimaOS, ma tâche vivait donc dans la mémoire vive.&#10;Elle a fonctionné parfaitement &lt;strong&gt;jusqu&amp;rsquo;au premier redémarrage&lt;/strong&gt;, qui l&amp;rsquo;a&#10;effacée sans un bruit.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-attention" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/&gt;&lt;path d="M12 9v4"/&gt;&lt;path d="M12 17h.01"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Attention&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Sur un système dont &lt;code&gt;/var&lt;/code&gt; est en tmpfs, &lt;code&gt;crontab -e&lt;/code&gt; semble fonctionner :&#10;la tâche s&amp;rsquo;affiche, elle se lance, tout a l&amp;rsquo;air normal. Le problème&#10;n&amp;rsquo;apparaît qu&amp;rsquo;au redémarrage suivant, parfois des semaines plus tard.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="deuxième-énigme--pourquoi-aucune-alerte-"&gt;Deuxième énigme : pourquoi aucune alerte ?&lt;/h2&gt;&#10;&lt;p&gt;C&amp;rsquo;est la question qui m&amp;rsquo;a le plus appris. Deux défauts se sont cumulés.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Un script qui ne se lance pas ne peut rien signaler.&lt;/strong&gt; Mon script envoie&#10;« échec » quand une étape échoue. Mais là, il n&amp;rsquo;a jamais démarré. Il ne&#10;restait que le délai de 26 heures pour me prévenir.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Le chien de garde redémarrait avec ce qu&amp;rsquo;il surveillait.&lt;/strong&gt; Uptime Kuma&#10;tourne sur le même serveur. À chaque redémarrage de l&amp;rsquo;après-midi, son&#10;compte à rebours de 26 heures repartait de zéro. Il aurait fini par&#10;m&amp;rsquo;alerter… si j&amp;rsquo;avais arrêté de redémarrer.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-lecon" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M9 18h6"/&gt;&lt;path d="M10 22h4"/&gt;&lt;path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Leçon&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Un chien de garde doit vivre ailleurs que ce qu&amp;rsquo;il garde. Quand le&#10;serveur tombe, la supervision qui tourne dessus tombe avec lui.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="la-correction--un-timer-systemd"&gt;La correction : un timer systemd&lt;/h2&gt;&#10;&lt;p&gt;Puisque &lt;code&gt;/etc&lt;/code&gt; est conservé, la tâche doit être déclarée là. J&amp;rsquo;ai remplacé&#10;la ligne cron par un &lt;strong&gt;timer systemd&lt;/strong&gt; : un couple de deux petits fichiers.&lt;/p&gt;&#10;&lt;p&gt;Le service dit &lt;strong&gt;quoi&lt;/strong&gt; lancer :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/systemd/system/sauvegarde.service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Sauvegarde restic nocturne&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;oneshot&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/chemin/vers/sauvegarde.sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le timer dit &lt;strong&gt;quand&lt;/strong&gt; le lancer :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/systemd/system/sauvegarde.timer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Lance la sauvegarde chaque nuit à 3 h 30&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Timer]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;OnCalendar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;*-*-* 03:30:00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Persistent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;timers.target&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La ligne &lt;code&gt;Persistent=true&lt;/code&gt; est le vrai gain par rapport à cron : si le&#10;serveur était éteint à 3 h 30, la sauvegarde est lancée dès le démarrage&#10;suivant au lieu d&amp;rsquo;être simplement sautée.&lt;/p&gt;&#10;&lt;p&gt;On active le timer, puis on vérifie la date du prochain lancement :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl daemon-reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now sauvegarde.timer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl list-timers sauvegarde.timer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Je n&amp;rsquo;ai pas considéré le problème réglé avant de l&amp;rsquo;avoir &lt;strong&gt;prouvé&lt;/strong&gt; : un&#10;redémarrage, puis &lt;code&gt;systemctl list-timers&lt;/code&gt; à nouveau. Le timer était&#10;toujours là.&lt;/p&gt;&#10;&lt;h2 id="lerreur-pendant-la-correction"&gt;L&amp;rsquo;erreur pendant la correction&lt;/h2&gt;&#10;&lt;p&gt;J&amp;rsquo;ai aussi fait une erreur en corrigeant. J&amp;rsquo;ai deux scripts aux noms&#10;proches : celui qui fait la sauvegarde complète, et un petit outil qui&#10;transmet ses arguments à restic. Mon premier service lançait… le second.&#10;Résultat : le journal ne contenait que l&amp;rsquo;aide de restic.&lt;/p&gt;&#10;&lt;p&gt;Depuis, ma documentation distingue clairement les deux, avec une phrase&#10;pour chacun : ce qu&amp;rsquo;il fait, et quand on l&amp;rsquo;utilise.&lt;/p&gt;&#10;&lt;h2 id="ce-que-jen-retiens"&gt;Ce que j&amp;rsquo;en retiens&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Un changement peut casser quelque chose qui n&amp;rsquo;a rien à voir avec&#10;lui.&lt;/strong&gt; J&amp;rsquo;avais redémarré pour tester SSH, pas les sauvegardes.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Connaître son système avant d&amp;rsquo;y appliquer ses habitudes.&lt;/strong&gt; &lt;code&gt;crontab -e&lt;/code&gt;&#10;est un bon réflexe sur une Debian, un piège sur ZimaOS.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Une absence de nouvelles n&amp;rsquo;est pas une bonne nouvelle.&lt;/strong&gt; Le silence&#10;peut vouloir dire « tout va bien » comme « rien ne s&amp;rsquo;est lancé ».&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Vérifier les tâches planifiées après chaque redémarrage&lt;/strong&gt;, au moins&#10;tant qu&amp;rsquo;on n&amp;rsquo;a pas prouvé qu&amp;rsquo;elles survivent.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Il me reste un chantier ouvert : déplacer ce chien de garde hors du&#10;serveur, pour qu&amp;rsquo;une panne complète déclenche enfin une alerte.&lt;/p&gt;&#10;</description></item><item><title>Zéro port ouvert : Cloudflare Tunnel pour le public, Tailscale pour le privé</title><link>https://journal.ange-bonkoski.fr/journal/zero-port-ouvert/</link><pubDate>Sun, 18 Oct 2026 10:00:00 +0200</pubDate><guid>https://journal.ange-bonkoski.fr/journal/zero-port-ouvert/</guid><category>homelab</category><category>réseau</category><category>cloudflare</category><category>tailscale</category><category>sécurité</category><description>&lt;p&gt;Pendant des semaines, mon serveur maison était joignable depuis Internet&#10;de la façon la plus classique qui soit : deux redirections de ports sur ma&#10;box, le 80 et le 443, vers un reverse proxy. Ça marchait. Et c&amp;rsquo;est&#10;justement le problème : ça marchait &lt;strong&gt;pour tout le monde&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;Aujourd&amp;rsquo;hui, ma box n&amp;rsquo;a plus &lt;strong&gt;aucune&lt;/strong&gt; redirection. Mon portfolio est&#10;toujours en ligne, et j&amp;rsquo;accède toujours à mes services privés depuis mon&#10;téléphone en 4G. Voici comment, et surtout pourquoi.&lt;/p&gt;&#10;&lt;h2 id="le-point-de-départ"&gt;Le point de départ&lt;/h2&gt;&#10;&lt;p&gt;Mon homelab est un vieux PC portable sous ZimaOS, qui fait tourner une&#10;dizaine de services dans des conteneurs Docker : mon portfolio, un&#10;gestionnaire de mots de passe (Vaultwarden), de la supervision, un filtre&#10;DNS…&lt;/p&gt;&#10;&lt;p&gt;Pour les rendre accessibles de l&amp;rsquo;extérieur, j&amp;rsquo;avais fait ce que font la&#10;plupart des tutoriels :&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;un enregistrement DNS qui pointe vers l&amp;rsquo;&lt;strong&gt;IP publique&lt;/strong&gt; de ma box ;&lt;/li&gt;&#10;&lt;li&gt;une redirection des ports 80 et 443 de la box vers le serveur ;&lt;/li&gt;&#10;&lt;li&gt;un reverse proxy (Nginx Proxy Manager) qui répartit les requêtes entre&#10;les services selon le nom de domaine demandé.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="pourquoi-ce-nétait-pas-acceptable"&gt;Pourquoi ce n&amp;rsquo;était pas acceptable&lt;/h2&gt;&#10;&lt;p&gt;Un port ouvert, c&amp;rsquo;est une porte d&amp;rsquo;entrée que n&amp;rsquo;importe qui peut essayer de&#10;pousser. Et sur Internet, quelqu&amp;rsquo;un essaie &lt;strong&gt;en permanence&lt;/strong&gt; : des robots&#10;balayent toutes les adresses IPv4 en continu, à la recherche d&amp;rsquo;un service&#10;mal configuré ou pas à jour.&lt;/p&gt;&#10;&lt;p&gt;Trois choses me gênaient en particulier :&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;mon coffre de mots de passe était joignable par le monde entier.&lt;/strong&gt; Il&#10;était protégé par un mot de passe maître et une double authentification,&#10;mais une seule faille dans Vaultwarden aurait suffi ;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;mon IP publique apparaissait dans mon DNS.&lt;/strong&gt; N&amp;rsquo;importe qui pouvait&#10;savoir où se trouve mon serveur, et donc ma connexion personnelle ;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;toute la sécurité reposait sur un seul logiciel&lt;/strong&gt;, le reverse proxy,&#10;en première ligne face à Internet.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Je me suis fixé une règle simple : &lt;strong&gt;ce qui doit être public l&amp;rsquo;est ; tout le&#10;reste ne doit même pas être visible.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h2 id="lidée--inverser-le-sens-de-la-connexion"&gt;L&amp;rsquo;idée : inverser le sens de la connexion&lt;/h2&gt;&#10;&lt;p&gt;Une redirection de port, c&amp;rsquo;est la box qui &lt;strong&gt;accepte&lt;/strong&gt; des connexions&#10;entrantes. Le pare-feu de la box, lui, bloque déjà tout ce qui entre sans&#10;avoir été demandé. Il suffit donc de ne rien lui demander d&amp;rsquo;accepter.&lt;/p&gt;&#10;&lt;p&gt;Le principe est le suivant : c&amp;rsquo;est le &lt;strong&gt;serveur&lt;/strong&gt; qui ouvre lui-même une&#10;connexion &lt;strong&gt;sortante&lt;/strong&gt; vers un service extérieur, et c&amp;rsquo;est par ce tuyau&#10;déjà ouvert que les visiteurs arrivent. Vu de la box, il n&amp;rsquo;y a qu&amp;rsquo;une&#10;connexion sortante, comme quand vous ouvrez un site web. Rien n&amp;rsquo;entre.&lt;/p&gt;&#10;&lt;p&gt;J&amp;rsquo;ai utilisé deux outils construits sur cette idée, un pour chaque usage.&lt;/p&gt;&#10;&lt;h2 id="le-chemin-public--cloudflare-tunnel"&gt;Le chemin public : Cloudflare Tunnel&lt;/h2&gt;&#10;&lt;p&gt;Mon portfolio doit rester accessible à n&amp;rsquo;importe quel recruteur, sans&#10;logiciel à installer. Pour lui, j&amp;rsquo;utilise &lt;strong&gt;Cloudflare Tunnel&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;Un petit conteneur, &lt;code&gt;cloudflared&lt;/code&gt;, tourne sur le serveur. Au démarrage, il&#10;ouvre une connexion chiffrée vers Cloudflare et la garde ouverte. Le&#10;domaine pointe vers Cloudflare, plus vers ma box :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Visiteur → DNS → Cloudflare (pare-feu applicatif, cache)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → tunnel (connexion sortante ouverte par le serveur)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → cloudflared → serveur web du portfolio&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le fichier Compose tient en quelques lignes. Le jeton qui identifie le&#10;tunnel n&amp;rsquo;y est pas écrit : il est lu dans un fichier &lt;code&gt;.env&lt;/code&gt; séparé, lisible&#10;seulement par son propriétaire.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cloudflared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cloudflare/cloudflared:latest&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tunnel --no-autoupdate run&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;TUNNEL_TOKEN=${TUNNEL_TOKEN} &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# lu dans .env, jamais en clair ici&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Au passage, mon IP publique a disparu du DNS : on ne voit plus que celles&#10;de Cloudflare.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-attention" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/&gt;&lt;path d="M12 9v4"/&gt;&lt;path d="M12 17h.01"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;Le prix de ce confort&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Cloudflare termine le chiffrement TLS : il voit passer le trafic du site&#10;en clair avant de le renvoyer dans le tunnel. Pour un portfolio public, ça&#10;ne me dérange pas. Pour un service qui manipule des données sensibles,&#10;c&amp;rsquo;est une vraie question de confiance. C&amp;rsquo;est d&amp;rsquo;ailleurs pour ça que mon&#10;coffre de mots de passe n&amp;rsquo;emprunte &lt;strong&gt;pas&lt;/strong&gt; ce chemin.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="les-chemins-privés--tailscale"&gt;Les chemins privés : Tailscale&lt;/h2&gt;&#10;&lt;p&gt;Pour tout le reste (coffre de mots de passe, administration, partage de&#10;fichiers, SSH), il n&amp;rsquo;y a qu&amp;rsquo;un seul public : moi. Pas besoin de les&#10;exposer au monde ; il suffit que &lt;strong&gt;mes appareils&lt;/strong&gt; puissent les joindre.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Tailscale&lt;/strong&gt; crée un réseau privé chiffré (basé sur WireGuard) entre mon&#10;serveur, mon PC, mon Mac et mon iPhone. Chaque appareil reçoit une adresse&#10;dans une plage réservée, qui n&amp;rsquo;a de sens que sur ce réseau.&#10;Et là encore, chaque appareil n&amp;rsquo;ouvre que des connexions sortantes : aucune&#10;redirection n&amp;rsquo;est nécessaire.&lt;/p&gt;&#10;&lt;p&gt;Restait un détail : je voulais garder une vraie adresse, avec un vrai&#10;certificat HTTPS, pour que les applications de mon gestionnaire de mots de&#10;passe fonctionnent comme avant. La solution tient en trois morceaux.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;1. Un DNS qui pointe vers une adresse privée.&lt;/strong&gt; Le sous-domaine du coffre&#10;renvoie l&amp;rsquo;adresse Tailscale du serveur. Tout le monde peut lire cet&#10;enregistrement, mais cette adresse ne mène nulle part si l&amp;rsquo;on n&amp;rsquo;est pas&#10;dans mon réseau Tailscale.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;2. Un certificat obtenu sans port ouvert.&lt;/strong&gt; Let&amp;rsquo;s Encrypt doit vérifier&#10;que je contrôle bien le domaine avant de délivrer un certificat. La méthode&#10;habituelle (le &lt;em&gt;défi HTTP&lt;/em&gt;) consiste à venir chercher un fichier sur mon&#10;serveur… ce qui est impossible, puisque plus rien n&amp;rsquo;est joignable. J&amp;rsquo;utilise&#10;donc le &lt;strong&gt;défi DNS&lt;/strong&gt; : le reverse proxy crée lui-même un enregistrement&#10;temporaire dans ma zone DNS, grâce à un jeton d&amp;rsquo;API Cloudflare limité à&#10;cette seule zone.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;3. Un relais pour le port 443.&lt;/strong&gt; Sur mon serveur, l&amp;rsquo;interface de ZimaOS&#10;occupe déjà le port 80, et le reverse proxy écoute sur d&amp;rsquo;autres ports. C&amp;rsquo;est&#10;Tailscale qui reçoit le 443 sur son interface et le relaie vers le reverse&#10;proxy :&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tailscale serve --bg --tcp &lt;span class="m"&gt;443&lt;/span&gt; tcp://localhost:&amp;lt;port-https-du-proxy&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-attention" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/&gt;&lt;path d="M12 9v4"/&gt;&lt;path d="M12 17h.01"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;La commande à ne jamais lancer&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;&lt;code&gt;tailscale serve reset&lt;/code&gt; efface &lt;strong&gt;tous&lt;/strong&gt; les relais configurés. Je l&amp;rsquo;ai&#10;appris en la lançant : mon coffre est devenu injoignable jusqu&amp;rsquo;à ce que je&#10;recrée le relais.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="vérifier-plutôt-que-supposer"&gt;Vérifier, plutôt que supposer&lt;/h2&gt;&#10;&lt;p&gt;Une fois les redirections supprimées dans l&amp;rsquo;interface de la box, je n&amp;rsquo;ai&#10;pas considéré que c&amp;rsquo;était fini. J&amp;rsquo;ai vérifié chaque promesse depuis&#10;l&amp;rsquo;&lt;strong&gt;extérieur&lt;/strong&gt;, avec mon iPhone en 4G (donc hors de mon réseau local) :&lt;/p&gt;&#10;&#10;&lt;div class="tableau" role="region" aria-label="Tableau" tabindex="0"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th class="aligne-left"&gt;Test&lt;/th&gt;&#10; &lt;th class="aligne-center"&gt;Tailscale coupé&lt;/th&gt;&#10; &lt;th class="aligne-center"&gt;Tailscale actif&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Portfolio&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;accessible&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;accessible&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Coffre de mots de passe&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;&lt;strong&gt;injoignable&lt;/strong&gt;&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;accessible&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;IP publique de la box&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;aucune réponse&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;—&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td class="aligne-left"&gt;Partages de fichiers&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;&lt;strong&gt;injoignables&lt;/strong&gt;&lt;/td&gt;&#10; &lt;td class="aligne-center"&gt;accessibles&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;J&amp;rsquo;ai aussi balayé l&amp;rsquo;adresse &lt;strong&gt;IPv6&lt;/strong&gt; publique du serveur. Contrairement à&#10;l&amp;rsquo;IPv4, une adresse IPv6 désigne directement la machine, sans traduction&#10;d&amp;rsquo;adresse par la box : c&amp;rsquo;est un oubli classique. Résultat : tous les ports&#10;testés fermés ou filtrés.&lt;/p&gt;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&lt;div class="encadre encadre-lecon" role="note"&gt;&#10; &lt;p class="encadre-titre"&gt;&#10; &#10; &#10; &lt;svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;path d="M9 18h6"/&gt;&lt;path d="M10 22h4"/&gt;&lt;path d="M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2z"/&gt;&lt;/svg&gt;&#10; &#10; &lt;span&gt;L&amp;#39;échec qui prouve que ça marche&lt;/span&gt;&#10; &lt;/p&gt;&#10; &#10; &lt;div class="encadre-contenu"&gt;&#10; &lt;p&gt;Plus tard, en ajoutant un nouveau service, j&amp;rsquo;ai oublié de cocher le défi&#10;DNS : la demande de certificat en défi HTTP a échoué. Let&amp;rsquo;s Encrypt n&amp;rsquo;avait&#10;pas pu joindre mon serveur depuis Internet. Cette erreur était la&#10;meilleure preuve possible que l&amp;rsquo;isolement tenait.&lt;/p&gt;&#10;&#10; &lt;/div&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 id="ce-que-jen-retiens"&gt;Ce que j&amp;rsquo;en retiens&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Ne pas confondre « accessible » et « exposé ».&lt;/strong&gt; Mes services privés&#10;sont accessibles partout où je vais, mais ne sont exposés à personne.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Séparer les chemins selon le public.&lt;/strong&gt; Un visiteur anonyme et moi&#10;n&amp;rsquo;avons pas besoin d&amp;rsquo;emprunter la même porte.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Tester depuis l&amp;rsquo;extérieur.&lt;/strong&gt; Depuis le Wi-Fi de la maison, tout semble&#10;toujours fonctionner. C&amp;rsquo;est en 4G qu&amp;rsquo;on voit ce qui est vraiment exposé.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Chaque choix a un coût.&lt;/strong&gt; Le tunnel me rend dépendant de Cloudflare :&#10;si le conteneur &lt;code&gt;cloudflared&lt;/code&gt; s&amp;rsquo;arrête, le portfolio tombe. Ma&#10;supervision me prévient dans ce cas.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Il reste une limite que j&amp;rsquo;assume : à l&amp;rsquo;intérieur de mon réseau local, les&#10;services écoutent encore sur toutes les interfaces. La prochaine étape est&#10;de réduire aussi cette surface-là.&lt;/p&gt;&#10;</description></item></channel></rss>