<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Networking on Bricklou &amp; Co</title><link>https://bricklou.ovh/tags/networking/</link><description>Recent content in Networking on Bricklou &amp; Co</description><generator>Hugo -- gohugo.io</generator><language>fr-fr</language><lastBuildDate>Mon, 27 Jul 2026 00:00:00 +0200</lastBuildDate><atom:link href="https://bricklou.ovh/tags/networking/index.xml" rel="self" type="application/rss+xml"/><item><title>Network Road Trip: jouons avec le réseau</title><link>https://bricklou.ovh/posts/2026/07/27/network-road-trip/</link><pubDate>Mon, 27 Jul 2026 00:00:00 +0200</pubDate><guid>https://bricklou.ovh/posts/2026/07/27/network-road-trip/</guid><description>&lt;p&gt;Dans post de début d&amp;rsquo;année sur la &lt;a href="https://bricklou.ovh/posts/2025/01/26/a-kubernetes-journey/"&gt;configuration de mon serveur Kubernetes&lt;/a&gt;, j&amp;rsquo;ai pu parler de
la manière dont j&amp;rsquo;ai mis en place mon infrastructure. Néanmoins, j&amp;rsquo;ai omis un détail quelque peu important : la gestion réseau et l&amp;rsquo;accès depuis l&amp;rsquo;extérieur.&lt;/p&gt;
&lt;h1 id="introduction" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Introduction&lt;/h1&gt;
&lt;p&gt;Dès que l&amp;rsquo;on souhaite héberger ses propres services depuis son domicile, nous arrivons inévitablement à ce moment crucial où il faut ouvrir les ports de notre
routeur pour permettre l&amp;rsquo;accès externe au serveur. J&amp;rsquo;ai moi-même utilisé cette approche pendant plusieurs années, en gérant les difficultés liées au changement
d&amp;rsquo;adresse IP imposé par mon fournisseur d&amp;rsquo;accès internet.&lt;/p&gt;
&lt;p&gt;Et si je vous disais qu&amp;rsquo;il existe une alternative ? Dans cet article, nous explorerons une approche différente qui permet l&amp;rsquo;accès externe tout en renforçant la
sécurité (par la fermeture complète du réseau local) et en éliminant la dépendance à l&amp;rsquo;adresse IP domestique.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note :&lt;/strong&gt; Cet article s&amp;rsquo;inspire grandement d&amp;rsquo;une publication sur le blog &lt;a href="https://blog.folf.fr/wireguard/"&gt;folf.fr&lt;/a&gt;, que j&amp;rsquo;ai ensuite amélioré, adapté et
étendu pour répondre à mes besoins spécifiques. Bien que l&amp;rsquo;approche de base reste similaire, j&amp;rsquo;ai ajouté mes propres optimisations, notamment l&amp;rsquo;intégration
avec NixOS, la gestion avancée des règles de pare-feu avec nftables (au lieu d&amp;rsquo;IP table), et des considérations pratiques issues de mon expérience
personnelle. Je vous invite à aussi lire son travail pour lui donner un peu plus de visibilité.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="lancienne-approche--le-port-forwarding" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
L&amp;rsquo;ancienne approche : le port forwarding&lt;/h1&gt;
&lt;p&gt;Pendant longtemps, l&amp;rsquo;accès à mes services depuis l&amp;rsquo;extérieur reposait sur une méthode classique : quelques règles de redirection de port sur ma box internet,
pointant directement vers mon cluster k3s à la maison. Ça fonctionne, c&amp;rsquo;est simple à mettre en place, mais ça a plusieurs inconvénients qui ont fini par me
déranger : mon adresse IP publique est exposée directement, avec tout ce que ça implique en scans, tentatives de connexion et autres joyeusetés qui trainent
sur internet. Mon réseau local devient une cible directe dès qu&amp;rsquo;un service exposé a une faille, puisque le port ouvert donne un accès direct à ma maison, pas
à une simple façade. Mon adresse IP change en plus régulièrement, mon fournisseur d&amp;rsquo;accès ne me fournissant pas d&amp;rsquo;IP fixe, ce qui m&amp;rsquo;oblige à jongler avec du
DNS dynamique. Et enfin, toute la configuration réseau dépend de ma box, un équipement que je ne maitrise pas totalement et sur lequel je n&amp;rsquo;ai qu&amp;rsquo;un contrôle
limité.&lt;/p&gt;
&lt;h1 id="la-nouvelle-approche--un-vps-en-façade" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
La nouvelle approche : un VPS en façade&lt;/h1&gt;
&lt;p&gt;L&amp;rsquo;idée est simple : au lieu d&amp;rsquo;exposer directement ma maison sur internet, je loue un petit VPS chez OVH avec une IP publique fixe, et c&amp;rsquo;est lui qui devient le
point d&amp;rsquo;entrée. Le trafic qui arrive dessus est ensuite relayé vers mon cluster à la maison via un tunnel WireGuard, et plus aucun port n&amp;rsquo;a besoin d&amp;rsquo;être ouvert
sur ma box.&lt;/p&gt;
&lt;pre class="mermaid"&gt;
flowchart TD
Internet([&amp;#34;Internet&amp;#34;])
subgraph VPS[&amp;#34;VPS (IP publique fixe)&amp;#34;]
NFT[&amp;#34;nftables : filtrage entrant &amp;#43; NAT&amp;#34;]
Haproxy[&amp;#34;haproxy : reverse proxy HTTP / TCP passthrough HTTPS&amp;#34;]
WgServer[&amp;#34;WireGuard (serveur du tunnel de relais)&amp;#34;]
end
subgraph Home[&amp;#34;Cluster k3s à la maison&amp;#34;]
WgClient[&amp;#34;WireGuard (client du tunnel de relais)&amp;#34;]
Ingress[&amp;#34;Ingress (Traefik) qui distribue vers les services&amp;#34;]
end
Internet --&amp;gt; NFT --&amp;gt; Haproxy --&amp;gt; WgServer
WgServer -- &amp;#34;tunnel WireGuard (seul chemin entre le VPS et la maison)&amp;#34; --&amp;gt; WgClient
WgClient --&amp;gt; Ingress
&lt;/pre&gt;
&lt;p&gt;Ce que ça change concrètement : ma box n&amp;rsquo;a plus aucune règle de redirection de port, la seule chose que fait mon serveur à la maison étant d&amp;rsquo;établir une
connexion sortante vers le VPS pour monter le tunnel WireGuard - un routeur grand public gère ça nativement, sans aucune configuration côté box. Si le VPS se
fait compromettre ou scanner dans tous les sens, c&amp;rsquo;est par ailleurs une machine jetable, réinstallable en quelques minutes, qui n&amp;rsquo;a accès qu&amp;rsquo;au strict
nécessaire de mon réseau local via le tunnel. L&amp;rsquo;IP publique associée à mon domaine est désormais fixe, plus besoin de DNS dynamique. Et en bonus, ce VPS va
aussi pouvoir me servir à héberger d&amp;rsquo;autres services, donc ce n&amp;rsquo;est pas une ressource dormante.&lt;/p&gt;
&lt;h1 id="le-tunnel-wireguard" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Le tunnel WireGuard&lt;/h1&gt;
&lt;p&gt;Il y a en réalité &lt;strong&gt;deux tunnels WireGuard distincts&lt;/strong&gt; chez moi, et il vaut mieux bien les différencier. D&amp;rsquo;un côté, un tunnel &lt;strong&gt;VPN personnel&lt;/strong&gt;, pour accéder à
mon réseau local depuis mon téléphone ou mon laptop en déplacement, qui existait déjà avant la migration vers le VPS. De l&amp;rsquo;autre, un tunnel de &lt;strong&gt;relais&lt;/strong&gt;,
celui qui nous intéresse ici, qui relie le VPS à la maison et qui sert uniquement à faire transiter le trafic entrant vers le cluster.&lt;/p&gt;
&lt;p&gt;Côté VPS, la configuration du tunnel de relais ressemble à ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;1&lt;/span&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;[Interface]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;2&lt;/span&gt;&lt;span&gt;PrivateKey &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;lt;clé privée du VPS&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;3&lt;/span&gt;&lt;span&gt;Address &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;10.66.66.1/24, fd42:42:42::1/64 # adresse du VPS dans le tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;4&lt;/span&gt;&lt;span&gt;ListenPort &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;51821 # port UDP sur lequel le VPS attend la maison&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;5&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;6&lt;/span&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;[Peer]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;7&lt;/span&gt;&lt;span&gt;PublicKey &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;lt;clé publique de la maison&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;8&lt;/span&gt;&lt;span&gt;AllowedIPs &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;10.66.66.2/32, fd42:42:42::2/128 # seule IP autorisée à traverser ce peer : la maison&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et côté maison (déclaré en NixOS) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-nix" data-lang="nix"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;1&lt;/span&gt;&lt;span&gt;networking&lt;span style="color:#ff7b72;font-weight:bold"&gt;.&lt;/span&gt;wireguard&lt;span style="color:#ff7b72;font-weight:bold"&gt;.&lt;/span&gt;interfaces&lt;span style="color:#ff7b72;font-weight:bold"&gt;.&lt;/span&gt;wg_vps &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;2&lt;/span&gt;&lt;span&gt; ips &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; [ &lt;span style="color:#a5d6ff"&gt;&amp;#34;10.66.66.2/32&amp;#34;&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#34;fd42:42:42::2/128&amp;#34;&lt;/span&gt; ]; &lt;span style="color:#8b949e;font-style:italic"&gt;# adresse de la maison dans le tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;3&lt;/span&gt;&lt;span&gt; peers &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; [{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;4&lt;/span&gt;&lt;span&gt; publicKey &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#34;&amp;lt;clé publique du VPS&amp;gt;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;5&lt;/span&gt;&lt;span&gt; endpoint &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#34;&amp;lt;IP publique du VPS&amp;gt;:51821&amp;#34;&lt;/span&gt;; &lt;span style="color:#8b949e;font-style:italic"&gt;# où joindre le VPS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;6&lt;/span&gt;&lt;span&gt; allowedIPs &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; [ &lt;span style="color:#a5d6ff"&gt;&amp;#34;10.66.66.1/32&amp;#34;&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#34;fd42:42:42::1/128&amp;#34;&lt;/span&gt; ]; &lt;span style="color:#8b949e;font-style:italic"&gt;# seule IP autorisée à traverser ce peer : le VPS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;7&lt;/span&gt;&lt;span&gt; persistentKeepalive &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;25&lt;/span&gt;; &lt;span style="color:#8b949e;font-style:italic"&gt;# garde le tunnel ouvert malgré le NAT de la box&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;8&lt;/span&gt;&lt;span&gt; }];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;9&lt;/span&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote
class="not-prose [&amp;_a]:text-teal-600 [&amp;_a]:hover:text-teal-500 rounded-md overflow-hidden my-2 bg-green-200 text-green-800"
&gt;
&lt;p
class="px-2 mt-0 font-semibold text-green-800 bg-green-400 text-green-800 bg-green-400"
&gt;
💡
Tip
&lt;/p&gt;
&lt;div class="px-2 py-1"&gt;
&lt;p&gt;Une erreur classique (que j&amp;rsquo;ai moi-même faite) est de penser que &lt;code&gt;AllowedIPs&lt;/code&gt; fonctionne comme une liste de contrôle d&amp;rsquo;accès, c&amp;rsquo;est-à-dire &amp;ldquo;quelles IPs ont le
droit de passer&amp;rdquo;. En réalité, ce champ définit une &lt;strong&gt;table de routage&lt;/strong&gt; : il indique quelles IPs doivent être routées à travers ce peer. Une mauvaise
compréhension de ce champ m&amp;rsquo;a valu un bon après-midi de dépannage à me demander pourquoi mon serveur n&amp;rsquo;avait plus accès à internet du tout. 😅&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h1 id="le-pare-feu-côté-vps" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Le pare-feu côté VPS&lt;/h1&gt;
&lt;p&gt;Le VPS ne doit laisser passer que le strict nécessaire. Sa configuration nftables ressemble grossièrement à ceci :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 1&lt;/span&gt;&lt;span&gt;# Entrant : uniquement SSH (sur un port non standard), HTTP/HTTPS et les ports WireGuard
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 2&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; tcp dport 2222 accept
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 3&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; tcp dport { 80, 443 } accept
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 4&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; udp dport { 51820, 51821 } accept
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 5&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 6&lt;/span&gt;&lt;span&gt;# Forward : uniquement ce qui doit transiter vers le tunnel
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 7&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; oifname &amp;#34;wg0&amp;#34; ct state new tcp dport { 22 } accept
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 8&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; oifname &amp;#34;wg0&amp;#34; ct state new udp dport { 51820 } accept
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 9&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;10&lt;/span&gt;&lt;span&gt;# NAT : redirection vers la maison via le tunnel
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;11&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; tcp dport 22 dnat ip to 10.66.66.2:22
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;12&lt;/span&gt;&lt;span&gt;iifname &amp;#34;ens3&amp;#34; udp dport 51820 dnat ip to 10.66.66.2:51820
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deux petits détails qui valent le coup d&amp;rsquo;être mentionnés. Le port &lt;strong&gt;22&lt;/strong&gt; est redirigé dans le tunnel pour matcher le SSH de mon serveur à la maison, tandis que
le SSH du VPS lui-même écoute sur &lt;strong&gt;2222&lt;/strong&gt; — pas vraiment un choix de sécurité réfléchi, plutôt de la configuration par pure flemme pour ne pas avoir à gérer
un conflit de port entre les deux machines. Et les ports 80 et 443 ne sont &lt;strong&gt;pas&lt;/strong&gt; redirigés directement au niveau du NAT : j&amp;rsquo;ai une configuration HAProxy qui
s&amp;rsquo;en charge, un cran plus haut.&lt;/p&gt;
&lt;h1 id="le-reverse-proxy-https" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Le reverse proxy HTTP(S)&lt;/h1&gt;
&lt;p&gt;Devant le cluster, j&amp;rsquo;ai mis en place un HAProxy fait le tri entre HTTP et HTTPS :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 1&lt;/span&gt;&lt;span&gt;frontend http-in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 2&lt;/span&gt;&lt;span&gt; bind *:80
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 3&lt;/span&gt;&lt;span&gt; mode http
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 4&lt;/span&gt;&lt;span&gt; default_backend k3s-http
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 5&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 6&lt;/span&gt;&lt;span&gt;backend k3s-http
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 7&lt;/span&gt;&lt;span&gt; server k3s 10.66.66.2:80
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 8&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt; 9&lt;/span&gt;&lt;span&gt;frontend https-in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;10&lt;/span&gt;&lt;span&gt; bind *:443
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;11&lt;/span&gt;&lt;span&gt; mode tcp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;12&lt;/span&gt;&lt;span&gt; default_backend k3s-https
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;13&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;14&lt;/span&gt;&lt;span&gt;backend k3s-https
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;15&lt;/span&gt;&lt;span&gt; server k3s 10.66.66.2:443 send-proxy-v2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le port 80 est traité en reverse proxy HTTP classique. Le port 443, en revanche, est traité en &lt;strong&gt;TCP passthrough&lt;/strong&gt; : haproxy ne déchiffre rien, il se contente
de faire suivre les octets tels quels jusqu&amp;rsquo;à l&amp;rsquo;ingress à la maison, qui garde la responsabilité de terminer le TLS. L&amp;rsquo;option &lt;code&gt;send-proxy-v2&lt;/code&gt; permet de
transmettre l&amp;rsquo;adresse IP réelle du client via le protocole PROXY, pour que l&amp;rsquo;ingress ne voie pas systématiquement l&amp;rsquo;IP du VPS comme unique origine du trafic.&lt;/p&gt;
&lt;p&gt;HAProxy me sert aussi de garde-fou en cas de souci avec mon serveur à la maison : des pages d&amp;rsquo;erreur personnalisées sont configurées pour chaque code
(400, 403, 408, 500, 502, 503, 504), avec un &lt;code&gt;deny_status 503&lt;/code&gt; explicite sur les deux frontends. Si le tunnel tombe ou que le serveur à la maison ne répond
plus, le visiteur tombe sur une page d&amp;rsquo;erreur &lt;em&gt;propre&lt;/em&gt; (dans la limite des pages par défaut de HAProxy) plutôt que sur une connexion qui traine ou se coupe brutalement.&lt;/p&gt;
&lt;h1 id="côté-cluster--cilium-et-les-interfaces-réseau" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Côté cluster : Cilium et les interfaces réseau&lt;/h1&gt;
&lt;p&gt;Petite parenthèse qui n&amp;rsquo;a rien à voir avec le sujet principal de cet article, mais qui a un impact direct sur la configuration du tunnel : depuis mon dernier
post, j&amp;rsquo;ai migré le CNI de mon cluster de flannel vers &lt;a href="https://cilium.io/"&gt;Cilium&lt;/a&gt;. Cette migration est majoritairement motivée par des défauts et bugs d&amp;rsquo;implémentation au niveau
de l&amp;rsquo;IPv6 dans flannel, notamment sur la gestion des redirections.&lt;/p&gt;
&lt;p&gt;Cette migration a eu un impact sur la configuration du tunnel : il a fallu explicitement indiquer à Cilium quelles interfaces réseau doivent être prises en
compte pour le routage des IP virtuelles de mes &lt;code&gt;LoadBalancer&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-nix" data-lang="nix"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681"&gt;1&lt;/span&gt;&lt;span&gt;devices &lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt; [ &lt;span style="color:#a5d6ff"&gt;&amp;#34;enp7s0&amp;#34;&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#34;wg_vps&amp;#34;&lt;/span&gt; &lt;span style="color:#a5d6ff"&gt;&amp;#34;wg0&amp;#34;&lt;/span&gt; ];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sans ça, le trafic entrant par le tunnel WireGuard n&amp;rsquo;était tout simplement pas pris en charge par le datapath eBPF de Cilium : les connexions arrivaient bien
jusqu&amp;rsquo;à l&amp;rsquo;interface, mais repartaient en &lt;code&gt;RST&lt;/code&gt; immédiatement. Un bon moment de capture de paquets avec &lt;code&gt;tcpdump&lt;/code&gt; a été nécessaire pour comprendre que Cilium
ignorait purement et simplement les paquets provenant d&amp;rsquo;une interface qu&amp;rsquo;il ne surveillait pas.&lt;/p&gt;
&lt;h1 id="état-actuel-et-reproductibilité" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
État actuel et reproductibilité&lt;/h1&gt;
&lt;p&gt;Contrairement au reste de mon infrastructure qui est gérée en NixOS et déployée via Flux, le VPS tourne sous &lt;strong&gt;Debian&lt;/strong&gt;, une machine &amp;ldquo;classique&amp;rdquo; que je ne
voulais pas intégrer à mes Flakes Nix. Pour assurer sa reproductibilité, j&amp;rsquo;ai introduit un provisioning entier via un playbook &lt;strong&gt;Ansible&lt;/strong&gt;, qui installe et
configure Docker, nftables, haproxy, un runner Forgejo Actions, un cache de registre Docker et WireGuard (utilisé par mon serveur) - de quoi reconstruire la
machine de zéro en quelques minutes si besoin.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai également ajouté quelques scripts pour simplifier l&amp;rsquo;ajout de nouveaux pairs WireGuard (typiquement pour un nouveau téléphone ou ordinateur), avec génération automatique
d&amp;rsquo;un QR code à scanner.&lt;/p&gt;
&lt;h1 id="limites-connues" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Limites connues&lt;/h1&gt;
&lt;p&gt;Cette configuration n&amp;rsquo;est pas exempte de dette technique. Notamment, le script de démarrage du tunnel WireGuard sur le VPS crée sa propre règle de masquerade
via &lt;code&gt;ip nat&lt;/code&gt;, en plus de celle déjà définie dans la configuration nftables — deux tables différentes qui cohabitent sans se marcher dessus pour l&amp;rsquo;instant, mais
que je devrais unifier un jour, dans la mesure où ça touche à la seule route d&amp;rsquo;entrée vers mon réseau local.&lt;/p&gt;
&lt;h1 id="conclusion" class="relative group flex flex-row lg:items-center pl-5 md:-left-5"&gt;
Conclusion&lt;/h1&gt;
&lt;p&gt;Cette migration du port forwarding vers une VPS en façade a réglé la plupart des problèmes qui me dérangeaient dans mon ancienne configuration : plus de ports
ouverts sur ma box, une IP publique fixe et jetable, et un réseau local qui reste fermé même en cas de compromission de la façade. Le tunnel WireGuard, une fois
la subtilité des &lt;code&gt;AllowedIPs&lt;/code&gt; bien comprise, est étonnamment simple à maintenir, et Ansible + NixOS me permettent de reconstruire l&amp;rsquo;ensemble de la chaîne sans
douleur en cas de pépin.&lt;/p&gt;
&lt;p&gt;Un autre avantage à mentionner : si un jour je dois déménager, je n&amp;rsquo;aurai rien à reconfigurer sur mon serveur. Dès qu&amp;rsquo;il aura de nouveau accès à internet,
l&amp;rsquo;ensemble de mes services sera à nouveau disponible. La classe, non ? 😎&lt;/p&gt;</description></item></channel></rss>