Sécuriser son homelab Proxmox : firewall, fail2ban et VPN Tailscale
Le lendemain de l’installation de Proxmox, les logs SSH affichaient déjà des tentatives de connexion.…
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.
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.
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 :
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é.
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 :
192.168.10.1/24192.168.20.1/24192.168.30.1/24192.168.40.1/24DHCP 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).
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) :
IoT (VLAN 20) :
Serveurs (VLAN 30) :
Stockage (VLAN 40) :
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.
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é :
192.168.30.103 pour Traefik)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.
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 :
192.168.10.2 par exemple)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.
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 :
et/emerging-malware, et/emerging-exploit, et/emerging-trojan, et/emerging-scanL’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.
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.
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).
Après six semaines de fonctionnement en production :
ping depuis un poste LAN vers la passerelle, comparé à la box directe. Imperceptible en pratique.nmap depuis une VM IoT de test.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
Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.