Avance 10 min de lecture · 2 154 mots

OPNsense sur Proxmox : remplacer sa box opérateur par un vrai firewall

Estimated reading time: 10 minutes

Le ZenWifi XT8 est un très bon point d’accès WiFi mesh. Son firewall intégré, en revanche, est une boîte noire : pas d’IDS, pas de visibilité sur le trafic inter-VLAN, pas de logs exploitables. Quand j’ai voulu comprendre pourquoi un équipement IoT généraient des connexions sortantes vers des IP chinoises à 3h du matin, l’interface ASUS m’a affiché… rien d’utile. C’est là que j’ai décidé de prendre le contrôle du firewall.

Architecture cible

OPNsense tourne en VM sur heighliner (MS-01, i9-13900H, Proxmox VE 8.3). La VM 207 lui est dédiée : 4 vCPU, 4 GB RAM, disque virtio de 20 GB sur le NVMe. Ce n’est pas du passthrough PCIe – j’utilise les bridges Proxmox standard. La perte de performance par rapport à un passthrough est négligeable pour un débit homelab de moins de 500 Mbps, et ça simplifie considérablement la gestion des mises à jour Proxmox.

Architecture réseau après migration :

Internet
    |
Box opérateur (mode routeur, double NAT)
    |
enp2s0 du MS-01 (2.5GbE)
    |
vmbr0 (bridge WAN Proxmox)
    |
VM OPNsense 207
    |
vmbr1 (bridge LAN Proxmox)
    |
VLANs : 10 (LAN), 20 (IoT), 30 (Serveurs), 40 (Stockage)
    |
TP-Link TL-SG108-M2 (trunk 802.1Q)
    |
ZenWifi XT8 (mode AP, VLAN tagging)

Mon FAI (Bouygues Telecom) ne propose pas le mode bridge sur la Bbox de manière simple et documentée. J’ai choisi de laisser la box en mode routeur et d’accepter le double NAT – ça casse certains protocoles P2P et complique le port forwarding depuis Internet, mais pour un homelab orienté services internes, c’est acceptable.

Installation OPNsense

Téléchargement de l’ISO OPNsense 24.7 (architecture amd64, image DVD) depuis le miroir officiel, upload dans le datastore local de Proxmox.

Création de la VM via l’interface Proxmox :

  • BIOS : OVMF (UEFI)
  • Disque : VirtIO Block, 20 GB, sur le NVMe local
  • CPU : 4 sockets, 1 core chacun (ou 1 socket, 4 cores – OPNsense s’en fiche)
  • RAM : 4096 MB, Ballooning désactivé (OPNsense gère mal le ballooning)
  • Réseau : deux interfaces réseau VirtIO – net0 attachée à vmbr0 (WAN), net1 attachée à vmbr1 (LAN)
  • L’installation depuis la console VNC est standard : choix du clavier, installation sur le disque VirtIO, définition du mot de passe root. Durée : environ 5 minutes.

    Au premier boot, OPNsense propose d’assigner les interfaces. vtnet0 devient WAN (DHCP vers la box), vtnet1 devient LAN avec l’IP provisoire 192.168.1.1.

    Pendant l’installation, le réseau du homelab n’est pas encore rerouté via OPNsense. Les VMs et LXC continuent de passer par la box. Ne basculer le trafic qu’une fois OPNsense complètement configuré.

    Configuration initiale via l’interface web

    L’interface web est accessible sur https://192.168.1.1 (certificat auto-signé à accepter). Première chose à faire : aller dans System > General Setup et changer le hostname en fw01 et le domaine en arewel.com.

    Configuration WAN

    Interfaces > WAN : DHCP (la box opérateur distribue une IP dans son sous-réseau). IPv6 : désactivé – la box Bouygues ne distribue pas d’IPv6 exploitable en double NAT.

    Configuration LAN et VLANs

    Je veux que OPNsense gère le routing inter-VLAN. La méthode la plus propre avec des bridges Proxmox sans passthrough : créer des interfaces VLAN sur l’interface LAN (vtnet1) directement dans OPNsense.

    Interfaces > Other Types > VLAN :

    VLAN ID Interface parent Description
    10 vtnet1 LAN
    20 vtnet1 IoT
    30 vtnet1 Serveurs
    40 vtnet1 Stockage

    Chaque VLAN est ensuite assigné comme interface dans Interfaces > Assignments, puis configuré avec une IP statique :

  • VLAN10 : 192.168.10.1/24
  • VLAN20 : 192.168.20.1/24
  • VLAN30 : 192.168.30.1/24
  • VLAN40 : 192.168.40.1/24
  • DHCP Server activé sur chaque interface (sauf Stockage 40, où toutes les IPs sont statiques).

    Côté Proxmox

    Le bridge vmbr1 doit être configuré en mode trunk (VLAN aware) pour laisser passer les tags 802.1Q. Dans /etc/network/interfaces sur heighliner :

auto vmbr1
iface vmbr1 inet manual
    bridge-ports enp3s0
    bridge-stp off
    bridge-fd 0
    bridge-vlan-aware yes
    bridge-vids 10 20 30 40

Le switch TP-Link TL-SG108-M2 est configuré en trunk sur le port relié à heighliner (port 1) et en access sur les ports des équipements finaux (NAS sur port 2 en PVID 40, AP ZenWifi sur port 3 en trunk pour les VLANs WiFi).

Règles firewall

La philosophie : deny-all par défaut sur WAN, allow-established+related automatique via les états de connexion, règles explicites pour ce qui doit passer.

WAN : aucune règle d’entrée – tout est bloqué par défaut.

LAN (VLAN 10) :

  • Allow from LAN to any (les postes du réseau local ont un accès complet)
  • Allow from LAN to Serveurs (redondant mais explicite)
  • IoT (VLAN 20) :

  • Allow from IoT to WAN (les équipements IoT accèdent à Internet)
  • Block from IoT to LAN (les ampoules connectées ne voient pas les postes)
  • Block from IoT to Serveurs (isolation complète)
  • Allow from IoT to 192.168.20.1 port 53 (DNS local via OPNsense)
  • Serveurs (VLAN 30) :

  • Allow from Serveurs to any (les services ont besoin d’accéder à tout)
  • Allow from LAN to Serveurs (les postes accèdent aux services)
  • Stockage (VLAN 40) :

  • Allow from Serveurs to Stockage (les LXC/VMs accèdent au NAS)
  • Allow from LAN to Stockage (les postes accèdent au NAS)
  • Block from IoT to Stockage
  • Les alias OPNsense simplifient la maintenance : HOMELAB_SERVERS liste les IPs fixes des LXC, NAS_IPS liste 192.168.40.10. Les règles référencent les alias, pas les IPs directes.

    Hairpin NAT : le problème que je n’avais pas anticipé

    Après avoir basculé le routage via OPNsense, tous mes services internes ont cessé d’être joignables via leur FQDN depuis l’intérieur du réseau. paperless.arewel.com résolvait bien vers l’IP publique (ou l’IP de Traefik en externe), mais les requêtes depuis l’intérieur du LAN arrivaient sur la box opérateur, qui ne savait pas quoi en faire.

    Le hairpin NAT (aussi appelé NAT loopback) résout ça : quand un client interne envoie une requête vers l’IP publique ou le FQDN externe d’un service qui est en réalité hébergé en interne, OPNsense redirige la connexion vers l’IP interne du service sans que le paquet sorte sur Internet.

    Configuration dans OPNsense : Firewall > NAT > Outbound, mode « Manual Outbound NAT ». Ajout d’une règle pour chaque service exposé :

  • Interface : LAN (et répéter pour IoT, Serveurs)
  • Source : réseau du VLAN concerné
  • Destination : IP interne du service (exemple : 192.168.30.103 pour Traefik)
  • Translation : Interface address
  • En pratique, j’ai créé une règle par VLAN source avec destination 192.168.30.0/24 (toute la plage Serveurs), ce qui couvre tous les services sans règle individuelle par service.

    Tester le hairpin NAT depuis un poste du réseau local avec curl -v https://paperless.arewel.com en regardant l’IP de destination dans la trace. Si tu vois l’IP interne de Traefik, le hairpin fonctionne.

    Migration du ZenWifi XT8 en mode AP

    C’est la partie la plus délicate de la migration – pas techniquement, mais parce que l’interface ASUS AiMesh n’est pas conçue pour ce cas d’usage.

    L’objectif : désactiver le routing et le DHCP sur le ZenWifi, ne garder que les fonctions WiFi et la gestion du mesh. OPNsense prend en charge tout le reste.

    Procédure sur le noeud principal du XT8 :

  • Accéder à l’interface d’administration (192.168.x.1 de la box ASUS)
  • Advanced Settings > WAN : changer le type de connexion en « Disabled »
  • Advanced Settings > LAN > DHCP Server : désactiver le serveur DHCP
  • Advanced Settings > LAN > IP : changer l’IP du XT8 à une IP dans le VLAN LAN gérée par OPNsense (192.168.10.2 par exemple)
  • Câbler le port LAN du XT8 sur le switch, qui est lui-même en trunk sur Proxmox
  • Les nœuds mesh secondaires (XT8 satellites) restent en mode AiMesh et se connectent au nœud principal via WiFi backhaul – ils n’ont pas besoin de reconfiguration individuelle.

    Ce qui a coincé : après avoir désactivé le DHCP sur le XT8, les appareils WiFi déjà connectés avaient des baux qui expiraient progressivement. Pendant la transition, certains appareils avaient une IP distribuée par le XT8 (plage 192.168.x.0/24) et d’autres une IP distribuée par OPNsense (plage 192.168.10.0/24 ou 192.168.20.0/24 selon le SSID). La solution a été d’attendre l’expiration des baux ou de forcer un renouvellement DHCP sur chaque appareil.

    La désactivation du DHCP sur le XT8 rend son interface d’administration inaccessible si tu ne lui as pas assigné d’IP statique au préalable. Assigne l’IP statique avant de couper le DHCP.

    IDS/IPS avec Suricata

    OPNsense intègre Suricata pour la détection et la prévention d’intrusion. L’activation se fait dans Services > Intrusion Detection > Administration.

    Configuration retenue :

  • Interface : WAN (analyse le trafic entrant)
  • Mode : IDS (détection uniquement, pas de blocage – pour commencer)
  • Ruleset : Emerging Threats Open (gratuit, mis à jour quotidiennement)
  • Catégories activées : et/emerging-malware, et/emerging-exploit, et/emerging-trojan, et/emerging-scan
  • L’impact en CPU mesuré après activation : environ 5 à 8 % de charge supplémentaire sur les 4 vCPU de la VM, à trafic WAN normal (~50 Mbps agrégé). C’est acceptable. En charge de téléchargement à 500 Mbps, ça monte à ~15 % – toujours dans les limites.

    Les alertes Suricata apparaissent dans Services > Intrusion Detection > Alerts. Après une semaine, les principaux déclenchements sont des scans de ports entrants (bots automatiques qui testent SSH, RDP, etc.) – exactement ce qu’on attend de voir sur une IP résidentielle exposée.

    Logs firewall vers Grafana

    OPNsense peut envoyer ses logs syslog vers un collecteur externe. Je l’ai dirigé vers le stack Loki sur hubble.arewel.com via Promtail.

    Configuration dans System > Log Files > Remote : protocole UDP, destination 192.168.30.50:514 (IP de la VM Loki/Promtail sur le VLAN Serveurs).

    Dans Promtail, une config supplémentaire pour parser les logs OPNsense (format BSD syslog avec les champs de filtrage firewall) :

    scrape_configs:
      - job_name: opnsense
        syslog:
          listen_address: 0.0.0.0:514
          labels:
            job: opnsense
        relabel_configs:
          - source_labels: [__syslog_message_hostname]
            target_label: host
    

    Dans Grafana, un dashboard simple affiche le nombre de paquets bloqués par règle et par heure – utile pour détecter un comportement anormal sur le VLAN IoT, par exemple.

    Mises à jour OPNsense

    Le processus de mise à jour est simple mais requiert une précaution systématique : sauvegarder la configuration XML avant chaque mise à jour.

    System > Backup > Download backup – le fichier XML contient toute la configuration (interfaces, règles, NAT, Suricata). En cas de mise à jour ratée ou d’incompatibilité, une restauration prend moins de 5 minutes.

    Mise à jour via System > Firmware > Status. OPNsense propose les mises à jour mineures (24.7.x → 24.7.y) directement depuis l’UI. Les mises à jour majeures (24.7 → 25.1) nécessitent parfois une procédure en ligne de commande – la documentation officielle est précise sur ce point.

    Je sauvegarde aussi le fichier XML dans le dépôt Git privé de la configuration homelab, avec les secrets expurgés (mots de passe remplacés par des placeholders).

    Résultats mesurés

    Après six semaines de fonctionnement en production :

  • Latence ajoutée par le firewall VM : 0,5 ms mesurée avec ping depuis un poste LAN vers la passerelle, comparé à la box directe. Imperceptible en pratique.
  • VLANs fonctionnels et isolés : un équipement IoT ne peut pas joindre un LXC sur le VLAN Serveurs – vérifié avec nmap depuis une VM IoT de test.
  • Suricata IDS actif : 127 alertes en une semaine, toutes des scans entrants automatisés – aucune intrusion détectée.
  • Logs firewall visibles dans Grafana : premier dashboard opérationnel avec le volume de trafic bloqué par heure et par règle.
  • Hairpin NAT fonctionnel : tous les services internes joignables via leur FQDN depuis n’importe quel VLAN autorisé.
  • Ce qui reste à faire : passer Suricata en mode IPS (blocage actif) sur les règles à fort ratio signal/bruit, et mettre en place des alertes Grafana sur les pics de blocage WAN pour détecter des scans ciblés plutôt que du bruit de fond automatisé.


    slug: opnsense-proxmox-firewall
    meta: OPNsense 24.x sur VM Proxmox : VLANs, Suricata IDS, hairpin NAT, migration ZenWifi en mode AP, logs vers Loki/Grafana. Latence ajoutée : 0,5 ms. (~152 chars)
    tags: OPNsense, firewall, Proxmox, VLAN, Suricata, IDS, réseau, homelab

    À propos de l'auteur

    Pascal Snijers

    Pascal Snijers — SRE & Observability Engineer dans le secteur bancaire belge. Avant ça : 25 ans de Telecom BSS/OSS — billing, provisioning, support Tier 3 EMEA — et des ordinateurs depuis 1987. Ici, j'applique les pratiques SRE à mon homelab Proxmox, SLO compris.

    Une remarque, un retour ?

    Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.

    Laisser un commentaire