Auteur/autrice : La Rédaction et Daily Home Lab

  • Securing your Proxmox Home Lab: Advanced Network Segmentation Guide with OPNsense

    The day my test server almost compromised my entire home network

    As an IT governance trainer, I often repeat this fundamental security axiom: « Never trust the default local network ». Yet, I fell into the classic beginner’s trap in my own Home Lab. During a routine audit of my Proxmox VE host, I realized that a simple Remote Code Execution (RCE) vulnerability on an LXD container hosting a public-facing test server would have allowed an attacker to pivot directly onto my backup NAS and personal devices.

    To align my infrastructure with ISO 27001 standards and best practices, I had to completely rethink my network governance. The solution? Strict VLAN segmentation orchestrated by a virtualized OPNsense firewall running on Proxmox, while bypassing the typical performance bottlenecks associated with network virtualization.

    Architecture & Governance: The Blueprint

    Effective governance requires mapping and segmenting traffic based on criticality. We will structure our network into 4 isolated zones:

    • VLAN 10 (Management): Access to Proxmox VE, OPNsense, switches, and PDU interfaces.
    • VLAN 20 (Trusted LAN): Personal computers, trusted mobile devices.
    • VLAN 30 (DMZ / Public): Reverse proxy, exposed Nextcloud or Vaultwarden instances.
    • VLAN 40 (IoT / Untrusted): Smart home devices and untrusted appliances.

    Step 1: Configuring a VLAN-Aware Linux Bridge in Proxmox

    To avoid needing multiple physical network interface cards (NICs), we configure Proxmox’s default Linux bridge (vmbr0) to natively handle VLAN tags. In the Proxmox Web UI:

    1. Navigate to System > Network.
    2. Edit the main bridge interface (typically vmbr0).
    3. Check the VLAN Aware box.
    4. Apply the configuration (or reboot the host).

    Step 2: Deploying OPNsense and Optimizing VirtIO Performance

    When provisioning the OPNsense VM, assign network interfaces using the VirtIO driver to achieve 10 Gbps speeds. However, virtualizing network adapters introduces a critical issue: hardware checksum offloading can corrupt packets routed through virtualized OPNsense instances.

    Crucial Action: Once OPNsense is installed, navigate to Interfaces > Settings and check the box to Disable Hardware Checksum Offload (as well as TSO and LRO). Reboot the firewall for changes to take effect.

    Step 3: Implementing Zero-Trust Firewall Rules

    The golden rule of governance is least privilege (Default Deny). By default, create an alias blocking all private address space (RFC 1918) for your DMZ and IoT zones.

    In the OPNsense firewall rules tab for your DMZ interface (VLAN 30), allow only:

    • DNS queries to the OPNsense gateway IP (UDP port 53).
    • Outbound traffic to the WAN (Internet) for package updates.
    • Explicitly block any inbound traffic targeting VLAN 10 (Admin) and VLAN 20 (Trusted).

    The Result: Enterprise-Grade Security at Home

    Thanks to this architecture, if my public-facing web server in the DMZ gets compromised, the attacker is isolated within a digital sandbox. They cannot scan my local LAN or access the Proxmox hypervisor. This setup proves that with the right open-source tools and a structured methodology, you can apply corporate-level security governance to any Home Lab.

  • Sécuriser son Home Lab Proxmox : Guide de segmentation réseau avancée avec OPNsense

    Le jour où mon serveur de test a failli compromettre tout mon réseau domestique

    En tant que formateur en gouvernance des SI, je répète souvent cette maxime de l’ANSSI : « Ne faites jamais confiance au réseau local par défaut ». Pourtant, j’ai moi-même commis l’erreur classique du débutant dans mon propre Home Lab. Lors d’un audit de routine de mon serveur Proxmox VE, j’ai réalisé qu’une simple vulnérabilité RCE (Remote Code Execution) sur un conteneur LXD hébergeant un serveur de test exposé aurait permis à un attaquant de pivoter directement vers mon NAS de sauvegarde et mes équipements personnels.

    Pour aligner mon infrastructure sur les exigences de la norme ISO 27001 et du guide d’hygiène informatique de l’ANSSI, j’ai dû repenser intégralement ma gouvernance réseau. La solution ? Une segmentation stricte par VLANs orchestrée par un pare-feu virtualisé OPNsense sous Proxmox, en évitant les pièges classiques de performances liés à la virtualisation réseau.

    Architecture technique et gouvernance : Le plan d’attaque

    Une bonne gouvernance impose de cartographier et de cloisonner les flux selon leur criticité. Nous allons structurer notre infrastructure autour de 4 zones étanches :

    • VLAN 10 (Administration) : Accès aux interfaces Proxmox VE, OPNsense, switches et PDU.
    • VLAN 20 (Trusted LAN) : PC personnels, smartphones de confiance.
    • VLAN 30 (DMZ / Public) : Reverse proxy, instances Nextcloud ou Vaultwarden exposées.
    • VLAN 40 (IoT / Untrusted) : Domotique et objets connectés.

    Étape 1 : Configuration du pont réseau (Bridge) VLAN-Aware sur Proxmox

    Pour éviter d’utiliser plusieurs cartes réseau physiques, nous configurons le pont Linux par défaut de Proxmox (vmbr0) pour qu’il gère les tags VLAN. Dans l’interface Web de Proxmox :

    1. Allez dans System > Network.
    2. Éditez le pont principal (souvent vmbr0).
    3. Cochez la case VLAN Aware.
    4. Appliquez les modifications (ou redémarrez l’hôte).

    Étape 2 : Déploiement d’OPNsense et optimisation des performances VirtIO

    Lors de la création de la machine virtuelle OPNsense, attribuez-lui des interfaces réseau basées sur le pilote VirtIO pour des performances maximales à 10 Gbps. Cependant, la virtualisation des cartes réseau introduit un problème majeur : le déchargement matériel des sommes de contrôle (Hardware Checksum Offloading) peut corrompre les paquets réseau passant par OPNsense.

    Action indispensable : Une fois OPNsense installé, rendez-vous dans Interfaces > Settings et cochez obligatoirement l’option Disable Hardware Checksum Offload (ainsi que TSO et LRO). Redémarrez ensuite le pare-feu.

    Étape 3 : Configuration des règles de filtrage étanches

    La règle d’or en gouvernance est le moindre privilège (Default Deny). Par défaut, créez une règle de blocage globale vers toutes les adresses privées (RFC 1918) sur votre zone DMZ et IoT.

    Dans l’onglet de configuration des règles de l’interface DMZ (VLAN 30) sur OPNsense, autorisez uniquement :

    • Les flux DNS vers l’IP d’OPNsense (port 53 UDP).
    • Le trafic sortant vers le WAN (Internet) pour les mises à jour.
    • Bloquez explicitement tout accès vers le VLAN 10 (Admin) et le VLAN 20 (Trusted).

    Résultat : Une posture de sécurité professionnelle à la maison

    Grâce à cette architecture, si mon serveur web en DMZ est compromis, l’attaquant se retrouve piégé dans une boîte de conserve numérique. Il lui est impossible de scanner mon réseau local ou d’accéder à l’hyperviseur Proxmox. Ce déploiement prouve qu’avec les bons outils open-source et une méthodologie rigoureuse, on peut appliquer une gouvernance de niveau entreprise au sein de son Home Lab.

  • Static HTML Hell (and How I Replaced It with a CSV‑Driven Gallery)

    Last month, while working on an artist’s portfolio (paintings/illustrations), I fell into the classic “100% static” website trap that quickly becomes unmanageable: every time a new piece was added, I had to open index.html, copy/paste a block, double-check image paths, alt text, tags… and then hope I didn’t break anything.

    The real problem wasn’t the “tech”—it was the workflow. The artist needed to be able to add a new artwork without touching HTML.

    So I separated the data (the list of artworks) from the rendering (the page) using a simple images.csv file loaded via JavaScript.

    Reference repo (full code):
    https://github.com/vladimir-monari/monartistique/blob/main/


    1) The idea: data in images.csv, automatic rendering in the DOM

    CSV structure (the “single source of truth”)

    I standardized an images.csv file with stable headers (important, because the code references them exactly as written):

    Nom de l'image,Chemin de l'image,Description de l'image,Tags
    Portrait Bleu,/img/bleu.jpg,Huile sur toile,abstrait-portrait
    Coucher de soleil,/img/soleil.jpg,Aquarelle,paysage-nature

    What each column is used for:

    • Nom de l’image: becomes the displayed title
    • Chemin de l’image: relative URL (e.g., /images/... or /img/...)
    • Description de l’image: descriptive text (also used as the image alt)
    • Tags: a list of tags separated by - (e.g., abstrait-portrait)

    That hyphen separator is intentional: it’s easy to type in Google Sheets, and trivial to parse in JS.


    2) index.html: a “shell” page (and that’s exactly what we want)

    In index.html, I kept:

    • everything structural (header, “about” section, footer)
    • the empty containers to be filled dynamically (#image-container, #tag-cloud)
    • dependencies (CSS + PapaParse) and the application script scripts.js
    • the fullscreen modal for large image display

    Key parts in your index.html:

    a) The critical containers

    <div id="tag-cloud"></div>
    <div id="image-container"></div>

    These are the “ports” where JavaScript injects the tag cloud and the gallery.

    b) The modal is already in place

    <div id="modal" class="modal">
    <span class="close">&times;</span>
    <img class="modal-content" id="modal-image">
    <div id="caption"></div>
    </div>

    This is a solid pattern: the structure is declarative in HTML, and JS only manipulates display, src, and text content.

    c) Dependencies: PapaParse is used, D3 is probably dead weight

    You currently load:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
    <script src="https://d3js.org/d3.v5.min.js"></script>

    PapaParse is indeed used. But D3 isn’t used in the current scripts.js (your tag cloud is built with vanilla DOM). So you can remove D3 to lighten the page—unless you plan to build a real visualization with it later.

    d) Google Tag Manager / Analytics

    You have both GTM and gtag. It works, but keep in mind:

    • it’s extra JavaScript weight
    • ideally document what’s being tracked in a README (avoids “black box” maintenance)

    3) scripts.js: the full pipeline (CSV → objects → DOM → tags → filters)

    a) Loading the CSV

    function loadCSV(callback) {
    fetch('images.csv')
    .then(response => response.text())
    .then(data => callback(data))
    .catch(error => console.error('Erreur lors du chargement du CSV:', error));
    }

    Implications:

    • images.csv must be in the same folder as index.html (or you need to adjust the path)
    • fetch() won’t work properly if you open the page via file:// (more on that in pitfalls)

    b) Parsing + generating image cards

    The core part:

    Papa.parse(data, {
    header: true,
    complete: function (results) {
    results.data.forEach(function (d) {
    if (!d["Nom de l'image"] || !d["Chemin de l'image"]) return;

    var container = document.createElement('div');
    container.classList.add('image-wrapper');
    container.dataset.tags = d['Tags'];

    var img = new Image();
    img.src = d["Chemin de l'image"];
    img.alt = d["Description de l'image"];
    img.classList.add("image-responsive");
    ...

    Good call: the early return prevents most empty rows / malformed CSV entries from causing issues.

    Then:

    • dataset.tags powers filtering
    • alt comes from the description (good accessibility/SEO reflex)
    • the modal opens on click

    c) Tag cloud + filtering

    You count tags with:

    d['Tags'].split('-').forEach(function (tag) {
    tags[tag] = (tags[tag] || 0) + 1;
    });

    …and build the tag cloud with font sizes proportional to frequency.


    4) The automation flow (the part that truly changes everything)

    The workflow I implemented (and that holds up over time):

    1. The artist updates a sheet (Google Sheets / Excel)
    2. Export to CSV
    3. Commit the CSV + images into the repo
    4. git push
    5. Deploy (GitHub Pages or similar) → the gallery updates automatically

    The big win: no more manual HTML editing for each new artwork.


    5) Pitfalls I hit (and the concrete fixes)

    1) Empty rows / incomplete objects (PapaParse)

    You already handle this with:

    if (!d["Nom de l'image"] || !d["Chemin de l'image"]) return;

    I’d keep that logic and also defensively handle missing tags:

    const rawTags = (d['Tags'] || '').trim();
    container.dataset.tags = rawTags;

    Otherwise, split('-') on undefined can crash.


    2) Local CORS issues (fetch + file://)

    Classic: double-clicking index.html isn’t enough.

    Fix: run a local server (VS Code Live Server, python -m http.server, etc.).
    In practice, Live Server solves it instantly during development.


    3) XSS / injection via CSV (the real sensitive one)

    In your current code, this line is risky:

    document.getElementById("caption").innerHTML = this.alt;

    Even if “it’s just a CSV”, it’s still input data. If one day a value contains HTML, it will be interpreted.

    Simple and robust fix: never use innerHTML for plain text:

    document.getElementById("caption").textContent = this.alt;

    This makes a custom sanitize() function far less critical (and you can reserve it for the rare cases where you truly need to inject HTML).


    4) Subtle bug: duplicate #tag-cloud container

    In index.html, you already have:

    <div id="tag-cloud"></div>

    But in displayTagCloud(), you create a new div with the same id and insert it after the <h3>:

    var tagCloud = document.createElement('div');
    tagCloud.id = 'tag-cloud';
    document.querySelector('#container h3').insertAdjacentElement('afterend', tagCloud);

    Result: you can end up with two elements with the same id (invalid HTML, weird behavior).

    Fix: reuse the existing container:

    function displayTagCloud(tags) {
    var tagCloud = document.getElementById('tag-cloud');
    tagCloud.innerHTML = ''; // reset
    ...
    }

    6) styles.css: what works (and what I’d tweak)

    What’s good:

    • simple, readable, consistent layout
    • .image-wrapper as inline-block: great for a “mosaic” gallery
    • fullscreen modal with dark overlay: perfect for artwork viewing

    Two practical notes:

    a) max-width: 100vh on .modal-content

    You currently have:

    .modal-content {
    max-width: 100vh;
    max-height: 90vh;
    }

    Using vh for width is unusual: on wide screens it can limit the image width in a counter-intuitive way. I generally prefer:

    .modal-content {
    max-width: 95vw;
    max-height: 90vh;
    }

    b) Visual performance

    As the gallery grows, consider:

    • loading="lazy" on images
    • dedicated thumbnails (avoid loading a 4000px image just to display a small preview)

    7) Future improvements (SEO, UX, performance) — a realistic roadmap

    UX / Accessibility

    • close the modal by clicking outside the image + pressing Escape
    • focus management (when the modal opens, focus the close button)
    • add aria-label to the close button

    Performance

    • img.loading = "lazy";
    • pagination / batch loading (12 at a time)
    • separate thumbnails + full-res images (e.g., thumb_path and full_path columns in the CSV)

    SEO

    • alt is already good, but you can go further:
      • artwork titles as <h4> (or at least better semantic structure)
      • JSON-LD (ImageObject or CreativeWork) if you want stronger indexing

    Security

    • avoid innerHTML for anything coming from the CSV (caption, descriptions, titles)
    • validate image paths (optional, but useful if multiple people edit the CSV)

    Conclusion

    The real benefit of a CSV + JS rendering approach is that it turns a fragile static site into a lightweight “DIY CMS”—no server, no database, no back office. For an artist portfolio, it’s the right compromise: easy to maintain, fast to load, and scalable.

    Full code (structure, index.html, images.csv, scripts.js, styles.css):
    https://github.com/vladimir-monari/monartistique/blob/main/

  • Tuto : Domotiser une porte de garage avec un Shelly Plus 1 et retour d’état réel

    Le problème du contrôle à l’aveugle : mon retour d’expérience

    Il y a quelques mois, j’ai failli enfermer le chat dans le garage. En quittant la maison en voiture, j’ai actionné ma vieille télécommande Somfy RTS sans vérifier si la voie était libre. C’est à ce moment précis que j’ai compris qu’il me fallait une solution intelligente pour domotiser ma motorisation de garage, mais surtout, obtenir un retour d’état 100 % fiable (ouvert ou fermé) dans Home Assistant. Pas question de me baser sur une simple estimation temporelle !

    La solution idéale ? Le micro-module Shelly Plus 1. Grâce à son contact sec isolé, il est parfait pour piloter une carte électronique de motorisation sans risquer d’y injecter du 230V.

    Pourquoi le Shelly Plus 1 est parfait pour cette tâche

    • Contact sec (Dry Contact) : Les bornes I (Input) et O (Output) sont totalement isolées de l’alimentation électrique du module (L/N).
    • Entrée SW configurable : On peut y brancher un capteur de fin de course magnétique pour connaître la position physique exacte de la porte.
    • Fiabilité locale : Pas besoin de cloud, il communique en WiFi directement via MQTT ou le protocole Shelly de Home Assistant.

    Étape 1 : Le schéma de câblage sécurisé

    Avant toute manipulation, coupez le disjoncteur général. Pour mon installation, j’ai alimenté le Shelly Plus 1 en 230V AC (bornes L et N). Si vous préférez la très basse tension, le Shelly accepte aussi le 12V ou 24-48V DC via un cavalier de configuration.

    Raccordez ensuite les bornes I et O du Shelly en parallèle sur l’entrée « bouton poussoir » (généralement nommée Start ou Cyc) de votre moteur de garage. Pour le capteur magnétique, fixez la partie filaire sur le châssis fixe de la porte de garage et l’aimant sur la section mobile de la porte (en position fermée). Raccordez les deux fils du capteur entre la borne SW et la borne L (si alimenté en 230V, ou GND si alimenté en DC).

    Étape 2 : Configuration du Shelly Plus 1

    Une fois le module sous tension, connectez-vous à son point d’accès Wi-Fi temporaire pour accéder à l’interface d’administration. Voici les réglages indispensables :

    • Timer Auto-Off : Activez un arrêt automatique (Auto-off) après 1 seconde. Cela permet de simuler un appui bref sur un bouton poussoir.
    • Input Mode : Configurez l’entrée SW en mode « Detached » (détachée). Cela évite que l’ouverture physique du capteur ne déclenche le relais par inadvertance.

    Étape 3 : Intégration Home Assistant

    Grâce à l’intégration native Shelly, le module remonte immédiatement. Pour obtenir une entité de type cover propre, j’ai créé un template dans mon fichier configuration.yaml qui combine l’action du relais et l’état de l’entrée SW. Désormais, je contrôle ma porte de garage de manière sécurisée, avec l’assurance visuelle qu’elle est bien fermée.

  • Measuring Real-World ITE Thermal Phase Shift: An ESPHome and DS18B20 Tutorial

    Introduction: Why Measure Real-World Phase Shift?

    During an external thermal insulation (ITE) retrofit, the choice of insulation material (such as wood fiber) is often driven by theoretical thermal phase shift. However, there is often a gap between theoretical calculations and real-world performance on historical walls. This tutorial explains how to accurately measure this phase shift by embedding DS18B20 sensors within the wall layers and integrating them into Home Assistant using ESPHome.

    Hardware Setup: Multi-Layer Integration

    For this measurement, we use an ESP32 microcontroller flashed with ESPHome and three waterproof DS18B20 temperature sensors wired on a OneWire bus:

    1. Outdoor Sensor (T_ext): Placed on the exterior facade, sheltered from direct sunlight.
    2. Interface Sensor (T_intf): Placed precisely between the old brick/stone wall and the new ITE insulation.
    3. Indoor Sensor (T_int): Placed on the inner surface of the wall.

    ESPHome Configuration for the OneWire Bus

    Here is the YAML configuration to integrate into your ESPHome node to report the three temperatures with ultra-high 12-bit resolution:

    dallas:
      - pin: GPIO23

    sensor:
      - platform: dallas
        address: 0x2c00000b12a34f28
        name: "ITE Outdoor Temperature"
      - platform: dallas
        address: 0x3c00000b12b45e12
        name: "Insulation Interface Temperature"
      - platform: dallas
        address: 0x4c00000b12c56f23
        name: "Indoor Wall Temperature"

    Analyzing Phase Shift in Home Assistant

    Thermal phase shift is the time delay between the peak outdoor temperature and the peak interface/indoor temperature. By exporting your Home Assistant data to InfluxDB and Grafana, you can easily calculate the time delta (t2 – t1) of daily maximums. High-performance wood fiber should yield a measured shift of 10 to 12 hours, successfully flattening the summer heat spikes.

  • Mesurer le déphasage thermique réel d’une ITE : Tuto ESPHome et DS18B20

    Introduction : Pourquoi mesurer le déphasage réel ?

    Lors d’une rénovation thermique par l’extérieur (ITE), le choix de l’isolant (comme la fibre de bois) est souvent guidé par le déphasage thermique théorique. Cependant, entre les calculs théoriques et la réalité physique du bâti ancien, il y a souvent un fossé. Ce tutoriel explique comment mesurer précisément ce déphasage en installant des sondes DS18B20 au cœur des couches de votre mur et en les intégrant dans Home Assistant via ESPHome.

    Le montage matériel : Intégration multi-couches

    Pour cette mesure, nous utilisons un microcontrôleur ESP32 flashé sous ESPHome et trois sondes de température étanches DS18B20 câblées en bus OneWire :

    1. Sonde Extérieure (T_ext) : Placée sur la façade extérieure, protégée du rayonnement direct du soleil.
    2. Sonde Interface (T_intf) : Placée précisément entre l’ancien mur en brique/pierre et le nouvel isolant ITE.
    3. Sonde Intérieure (T_int) : Placée sur la surface intérieure du mur.

    Configuration ESPHome pour le bus OneWire

    Voici la configuration YAML à intégrer dans votre nœud ESPHome pour remonter les trois températures de manière ultra-précise avec une résolution de 12 bits :

    dallas:
      - pin: GPIO23

    sensor:
      - platform: dallas
        address: 0x2c00000b12a34f28
        name: "Température Extérieure ITE"
      - platform: dallas
        address: 0x3c00000b12b45e12
        name: "Température Interface Isolant"
      - platform: dallas
        address: 0x4c00000b12c56f23
        name: "Température Intérieure Mur"

    Analyse du déphasage sous Home Assistant

    Le déphasage thermique correspond au retard temporel entre le pic de température extérieure et le pic de température à l’interface ou à l’intérieur. En exportant vos données de Home Assistant vers InfluxDB et Grafana, vous pouvez facilement calculer le delta temporel (t2 – t1) des maximums journaliers. Une fibre de bois performante doit révéler un déphasage mesuré d’environ 10 à 12 heures, lissant efficacement les pics de chaleur estivaux.

  • Sécuriser le LAN familial : Double filtrage DNS et isolation par VLANs avec OPNsense et AdGuard Home

    Le défi de la gouvernance numérique au sein du foyer

    En tant qu’architectes de nos propres infrastructures domestiques, nous appliquons souvent des règles de sécurité strictes au bureau, mais laissons le réseau familial vulnérable. Entre les objets connectés (IoT) bavards, les consoles des enfants et les ordinateurs portables professionnels des parents, la surface d’attaque est immense. Pour sécuriser la vie numérique de la famille sans impacter l’expérience utilisateur, une simple clé WPA2 globale ne suffit plus. La solution ? L’isolation par VLAN combinée à un filtrage DNS granulaire et dynamique.

    Étape 1 : Segmentation réseau (VLAN) sous OPNsense

    La première règle d’or de la sécurité est le cloisonnement. Nous allons segmenter notre réseau en trois zones distinctes à l’aide de VLANs configurés sur notre routeur/pare-feu OPNsense :

    • VLAN 10 (Parents/Admin) : Accès total à l’interface d’administration et à internet.
    • VLAN 20 (Kids) : Accès internet filtré, aucune communication possible avec le VLAN 10 ou l’IoT.
    • VLAN 30 (IoT) : Accès internet restreint au strict minimum, isolation complète du reste du réseau.

    Pour cela, rendez-vous dans Interfaces > Other Types > VLAN sur OPNsense. Créez vos interfaces, puis définissez des règles de pare-feu strictes dans Firewall > Rules pour interdire le trafic inter-VLAN (notamment du VLAN 20/30 vers le VLAN 10).

    Étape 2 : Configuration d’AdGuard Home pour un filtrage par profil

    Plutôt que de déployer plusieurs serveurs de filtrage, nous allons utiliser les fonctionnalités avancées d’AdGuard Home pour appliquer des politiques de sécurité et de contrôle parental différenciées selon les clients.

    Dans l’interface d’AdGuard Home, accédez à la section Paramètres du client. Vous pouvez y ajouter des appareils spécifiques ou des sous-réseaux entiers (par exemple, la plage IP du VLAN 20 des enfants). Pour ce profil « Kids », activez :

    • Le blocage des services spécifiques (TikTok, YouTube restreint, Discord selon l’âge).
    • La recherche sécurisée (SafeSearch) obligatoire sur Google, Bing et YouTube.
    • L’utilisation des serveurs DNS amont de type « Family Protection » (comme Cloudflare 1.1.1.3).

    Étape 3 : Verrouiller les échappatoires (Contrecarrer le contournement du DNS)

    Les adolescents sont astucieux. Si un enfant configure manuellement le DNS 8.8.8.8 sur sa console ou son smartphone, il contournera AdGuard Home. Pour empêcher cela, nous devons mettre en place une règle de NAT Port Forward sur OPNsense.

    Créez une règle de redirection de port (DNAT) pour intercepter toutes les requêtes sortantes sur le port 53 (UDP/TCP) qui ne sont pas destinées à l’IP de votre serveur AdGuard Home, et redirigez-les de force vers ce dernier. Faites de même pour le port 853 (DNS over TLS) pour bloquer ou rediriger le DNS sécurisé tiers.

    Conclusion

    En combinant la puissance de routage d’OPNsense et la flexibilité d’AdGuard Home, vous obtenez une infrastructure domestique digne d’une entreprise. Vos données personnelles sont isolées des objets connectés potentiellement vulnérables, et la navigation de vos enfants est protégée de manière transparente et centralisée.

  • Securing the Family LAN: Dual DNS Filtering and VLAN Isolation with OPNsense and AdGuard Home

    The Challenge of Digital Governance in the Smart Home

    As architects of our own home labs, we often apply strict security rules at work but leave our family network vulnerable. Between chatty IoT devices, children’s consoles, and parents’ work laptops, the attack surface is massive. To secure the family’s digital life without degrading the user experience, a simple global WPA2 key is no longer enough. The solution? VLAN isolation combined with granular, dynamic DNS filtering.

    Step 1: Network Segmentation (VLAN) on OPNsense

    The first golden rule of security is compartmentalization. We will segment our network into three distinct zones using VLANs configured on our OPNsense router/firewall:

    • VLAN 10 (Parents/Admin): Full access to the admin interface and the internet.
    • VLAN 20 (Kids): Filtered internet access, zero communication allowed with VLAN 10 or the IoT network.
    • VLAN 30 (IoT): Internet access restricted to the bare minimum, completely isolated from the rest of the network.

    To do this, navigate to Interfaces > Other Types > VLAN on OPNsense. Create your interfaces, then define strict firewall rules in Firewall > Rules to block inter-VLAN traffic (especially from VLAN 20/30 to VLAN 10).

    Step 2: Configuring AdGuard Home for Profile-Based Filtering

    Instead of deploying multiple filtering servers, we will use the advanced features of AdGuard Home to apply customized security and parental control policies based on the client.

    In the AdGuard Home UI, go to the Client Settings section. Here, you can add specific devices or entire subnets (such as the IP range of the Kids’ VLAN 20). For this « Kids » profile, enable:

    • Block specific services (TikTok, YouTube restricted, Discord depending on age).
    • Enforced SafeSearch on Google, Bing, and YouTube.
    • Upstream DNS servers set to « Family Protection » (like Cloudflare 1.1.1.3).

    Step 3: Blocking the Bypasses (Thwarting DNS Circumvention)

    Kids are tech-savvy. If a child manually sets their DNS to 8.8.8.8 on their console or smartphone, they will bypass AdGuard Home. To prevent this, we must set up a NAT Port Forward rule on OPNsense.

    Create a port redirection rule (DNAT) to intercept all outgoing queries on port 53 (UDP/TCP) that are not destined for your AdGuard Home IP, and forcibly redirect them to it. Do the same for port 853 (DNS over TLS) to block or redirect third-party secure DNS.

    Conclusion

    By combining the routing power of OPNsense and the flexibility of AdGuard Home, you achieve an enterprise-grade home network. Your personal data is isolated from potentially vulnerable smart devices, and your children’s browsing is protected seamlessly and centrally.

  • Optimizing Multi-Layer Forest Garden Irrigation: Calculating VPD with ESP32 and Home Assistant

    The Challenge of Water Management in a Multi-Layer Ecosystem

    In a forest garden designed according to permaculture principles, vegetation is structured in several vertical layers: from the canopy to ground covers, including fruit shrubs. Automating the irrigation of this type of ecosystem with simple soil moisture sensors poses a major problem: microclimate disparity. The intermediate shrub layer undergoes a different water stress compared to the ground cover layer, which is often protected by thick mulch.

    To solve this problem with ultra-precision, we will abandon capacitive soil probes (which oxidize and drift over time) to focus on a much more reliable biophysical metric: Vapor Pressure Deficit (VPD). VPD precisely measures the atmospheric pull on the water contained in plant leaves, indicating their actual transpiration rate.

    The IoT Architecture: Environmental Sensors and ESP32 under ESPHome

    Our architecture is based on the deployment of ESP32 modules housed in 3D-printed waterproof enclosures (IP65), positioned at different heights corresponding to the forest garden strata:

    • Layer 1 (Ground cover): DHT22 sensor placed 10 cm above the ground, under the mulch.
    • Layer 2 (Shrubs): BME280 sensor placed 1.5 m high, in the heart of the berry bushes.

    These sensors measure ambient temperature and relative humidity. Data is transmitted via Wi-Fi using the MQTT protocol to our Home Assistant home automation server.

    Real-Time VPD Calculation in Home Assistant

    VPD is expressed in kiloPascals (kPa). To calculate it dynamically, we use template integration in Home Assistant. Here is the mathematical formula implemented to calculate the saturated vapor pressure (VPsat) and the actual vapor pressure (VPact) to get the VPD:

    template:
      - sensor:
          - name: "Shrub Layer VPD"
            unit_of_measurement: "kPa"
            state: >-
              {% set T = states('sensor.bme280_temperature') | float %}
              {% set RH = states('sensor.bme280_humidity') | float %}
              {% set VPsat = 0.61078 * e ** ((17.27 * T) / (T + 237.3)) %}
              {% set VPact = VPsat * (RH / 100.0) %}
              {{ (VPsat - VPact) | round(2) }}

    Smart and Resilient Irrigation Automation

    Using this VPD value, we program a localized, water-saving irrigation rule. If the VPD of the shrub layer exceeds 1.2 kPa (moderate water stress zone for young shrubs) while the soil is not saturated, a low-power Shelly Pro 1 solenoid valve triggers a targeted drip system for 15 minutes.

    This approach respects permaculture design by preventing water waste while keeping plants in their transpiration comfort zone, thus limiting the development of fungal diseases favored by stagnant ground moisture.

  • Optimiser l’irrigation d’un jardin-forêt par strate : Calcul du VPD avec ESP32 et Home Assistant

    Le défi de la gestion de l’eau dans un écosystème multi-strate

    Dans un jardin-forêt conçu selon les principes de la permaculture, la végétation est organisée en plusieurs strates verticalisées : de la canopée aux plantes couvre-sol, en passant par les arbustes fruitiers. Automatiser l’irrigation de ce type d’écosystème avec de simples sondes d’humidité au sol pose un problème majeur : la disparité des microclimats. La strate arbustive intermédiaire subit un stress hydrique différent de la strate rampante, souvent protégée par un paillage dense (mulch).

    Pour résoudre ce problème de manière ultra-précise, nous allons abandonner les sondes de sol capacitives (qui s’oxydent et dérivent avec le temps) pour nous concentrer sur une métrique biophysique bien plus fiable : le Déficit de Pression de Vapeur (VPD – Vapor Pressure Deficit). Le VPD permet de mesurer précisément la force d’attraction de l’atmosphère sur l’eau contenue dans les feuilles des plantes, indiquant ainsi leur taux de transpiration réel.

    L’architecture IoT : Sondes environnementales et ESP32 sous ESPHome

    Notre architecture repose sur le déploiement de modules ESP32 abrités dans des boîtiers étanches imprimés en 3D (IP65), positionnés à différentes hauteurs correspondant aux strates du jardin-forêt :

    • Strate 1 (Couvre-sol) : Capteur DHT22 placé à 10 cm du sol, sous le paillage.
    • Strate 2 (Arbustive) : Capteur BME280 placé à 1,5 m de hauteur, au cœur des buissons de baies.

    Ces capteurs mesurent la température et l’humidité relative de l’air. Les données sont transmises en Wi-Fi via le protocole MQTT à notre serveur domotique Home Assistant.

    Calcul du VPD en temps réel dans Home Assistant

    Le VPD s’exprime en kiloPascals (kPa). Pour le calculer de manière dynamique, nous utilisons l’intégration de templates dans Home Assistant. Voici la formule mathématique implémentée pour calculer la pression de vapeur saturante (VPsat) et la pression de vapeur réelle (VPact) afin d’obtenir le VPD :

    template:
      - sensor:
          - name: "VPD Strate Arbustive"
            unit_of_measurement: "kPa"
            state: >-
              {% set T = states('sensor.bme280_temperature') | float %}
              {% set RH = states('sensor.bme280_humidity') | float %}
              {% set VPsat = 0.61078 * e ** ((17.27 * T) / (T + 237.3)) %}
              {% set VPact = VPsat * (RH / 100.0) %}
              {{ (VPsat - VPact) | round(2) }}

    Automatisation intelligente et résiliente de l’irrigation

    Grâce à cette valeur de VPD, nous programmons une règle d’irrigation locale et économe. Si le VPD de la strate arbustive dépasse 1.2 kPa (zone de stress hydrique modéré pour les jeunes arbustes) alors que le sol n’est pas saturé, une électrovanne basse consommation Shelly Pro 1 déclenche un goutte-à-goutte ciblé pendant 15 minutes.

    Cette approche permet de respecter le design permacole en évitant le gaspillage d’eau tout en maintenant les plantes dans leur zone de confort de transpiration, limitant ainsi le développement des maladies cryptogamiques (champignons) favorisées par une humidité stagnante au sol.