Skip to content

Fondations réseau homelab avec UniFi

Mon homelab a démarré comme beaucoup de labs : la box FAI en routeur, tout le monde sur le même LAN, un Proxmox sur un mini PC, le NAS sur le switch, le Wi‑Fi pour le reste. Ça suffit pour installer GitLab, Jellyfin, des VMs. Le réseau ne pose pas de question tant qu’on n’en pose pas.

Les questions ont commencé quand j’ai empilé : trois nœuds Proxmox, un Synology avec les backups et le media, des objets IoT, Home Assistant, un Wi‑Fi invité. Sur un LAN plat, tout voit tout. On peut créer des VLANs dans l’UI, mais sans firewall explicite entre eux, le routage Internal → Internal finit souvent en allow-all. Les VLANs seuls ne filtrent rien.

Concrètement chez moi : l’IoT devait joindre HA en MQTT mais pas le NAS ; le lab monte le NFS sur le Synology ; le PC Windows ouvre les partages en SMB ; les invités ne doivent pas toucher GitLab. Impossible à tenir proprement sur un seul subnet.

J’ai arrêté d’ajouter des services et j’ai investi dans le réseau avant de retourner sur k3s et les playbooks Ansible.

Avant : une prise IoT peut, en théorie, scanner le NAS et les VMs. Après : l’IoT passe par des ALLOW ciblés (Pi-hole, HA) puis des BLOCK sur Trusted et Untrusted. Le lab monte le NAS en NFS (port 2049) ; le PC en SMB (445) ; Guest est isolé.

L’anecdote du weekend : j’avais une règle ALLOW « IoT → Home Assistant », mais sous le BLOCK « IoT → Untrusted ». UniFi bloquait tout le vlan 50, donc .204 aussi. MQTT mort. L’ordre des règles compte autant que l’action.

Ce que j’ai acheté (et pourquoi pas avant)

Section titled “Ce que j’ai acheté (et pourquoi pas avant)”

L’ordre compte : la gateway avant le re-tag des ports, le switch manageable avant de multiplier les VLANs Wi‑Fi.

BriqueRôlePourquoi maintenant
UniFi Cloud Gateway FiberRoutage inter-VLAN, firewall zone-based, DHCP/DNS par réseauUn seul endroit pour filtrer et documenter le trafic
USW Flex 2.5GSwitch, ports taggés VLANLe LAN plat ne scale pas quand Main / IoT / Guest partagent le même fil
AP UniFi (déjà en place)Wi‑Fi par réseauInvités et IoT hors du Wi‑Fi « maison »
Synology DS423+NAS sur Trusted (20)Données hors du vlan lab
3× Proxmox (OptiPlex, Firebat, …)Compute sur Untrusted (50)Forge, media, k3s on-demand

Je n’ai pas pris OPNsense : j’avais déjà l’écosystème UniFi, et la CG Fiber tient routage + firewall + API locale. Les tutos homelab tournent souvent autour d’OPNsense ; le principe (segmenter, filtrer, vérifier) est le même.

  • Oui : plan d’adressage, règles firewall, DNS, NFS/SMB, IoT/HA, export API, pièges que j’ai touchés.
  • Non : tuto « installer UniFi depuis zéro », renumérotation massive des IPs, Terraform UniFi day 1, k3s (article suivant).

Stack logicielle : UniFi Network 10.x, firewall zone-based, policies ordonnées, API Integration pour auditer sans cliquer dans l’UI à chaque fois.

  1. Box FAI en WAN seulement ; CG Fiber comme gateway LAN.
  2. Switch + câblage ; ports taggés par VLAN.
  3. Réseaux UniFi (Main, Trusted, IoT, Untrusted, Guest).
  4. DHCP/DNS par réseau (Pi-hole, pas tout sur la gateway).
  5. Règles firewall user avant les BLOCK larges ; Reorder dans Internal → Internal.
  6. Tests (NFS, SMB, MQTT, Guest téléphone).
  7. Export API régulier pour figer la vérité.

Un weekend de durcissement et de doc — pas une refonte d’adressage. Si je recommençais : segmenter avant la troisième VM « forge », pas après GitLab et Vault.

Tout l’inter-VLAN passe par la gateway. Les flèches importantes sur le schéma : tout transite par la CG (point d’audit), Wi‑Fi et filaire partagent les mêmes VLANs, le NAS n’est pas sur le vlan lab.

NAS et Pi Zero sur Trusted ; Proxmox, GitLab, Vault, HAOS sur Untrusted.

J’aligne l’id VLAN sur le 3ᵉ octet quand je peux : vlan 20 → 192.168.20.x. En debug (ping, logs UniFi, tcpdump) ça évite de chercher.

VLANNomSubnetRôle
1Default192.168.0.0/24UniFi ; DHCP off
10Main192.168.10.0/24PC Windows, Wi‑Fi quotidien
20Servers-Trusted192.168.20.0/24NAS 192.168.20.20, Pi-hole 192.168.20.2
40IoT192.168.40.0/24Objets connectés
50Servers-Untrusted192.168.50.0/24PVE, GitLab, Vault, HAOS
60Guest192.168.60.0/24Invités, zone DMZ, isolation réseau

Untrusted (50) chez moi = lab / compute, pas « zone sans secrets » : GitLab et Vault y tournent. C’est séparé du NAS et des données long terme sur vlan 20.

Exception : Guest est vlan 60 (subnet .60), pas vlan 2 — j’ai aligné l’id sur le 3ᵉ octet après un premier réseau Guest mal calé.

pve03 (forge) et pve02 (media) restent allumés. pve01 (k3s Ansible) je ne lance que quand j’en ai besoin — conso et bruit, pas de cluster 24h pour l’instant.

Synology sur Trusted. Deux protocoles, deux règles firewall — pas un gros « allow vers le NAS ».

ClientVLANProtoPort
Proxmox, GitLab, mediastack50NFS2049
PC Windows10SMB445

Proxmox monte NFS pour backups et media ; Windows ouvre \\DS423 en SMB. L’IoT n’a ni l’un ni l’autre.

DNS : deux Pi-hole, pas les mêmes clients

Section titled “DNS : deux Pi-hole, pas les mêmes clients”
InstanceIPVLANRôle
Pi Zero 2W192.168.20.220Filtrage général
LXC sur pve03192.168.50.250Split DNS lab (GitLab, Vault), unbound

Main et lab poussent les deux + un fallback public en DHCP. IoT : seulement 192.168.20.2 en primaire et 1.1.1.1 en secours. Pas 192.168.50.2 — vlan 50 est bloqué pour l’IoT.

J’ai choisi ce secours public plutôt que deux Pi-hole filtrés (Gravity Sync + exception firewall vers .50.2:53). Si le Pi Zero tombe, les objets IoT gardent du DNS ; ils perdent le filtrage sur le fallback, mais les prises MQTT vers HA continuent. Sans sync, deux Pi-hole = listes qui divergent — à éviter ou à outiller.

Règles firewall DNS : toujours IP + port 53, jamais « tout le vlan Trusted ».

Firewall : l’ordre compte plus que l’action

Section titled “Firewall : l’ordre compte plus que l’action”

UniFi Network 10.x : zones Internal, DMZ (Guest), External. Policies Internal → Internal pour presque tout mon cas. La première règle qui matche gagne. Il y a un catch-all système Allow All Traffic ; mes règles user doivent être plus fines et au-dessus des BLOCK larges.

L’ordre ne se change pas depuis la Policy Table globale. Il faut Settings → Policy Engine → Zones → Internal → Internal, puis Reorder en bas de liste. Si Reorder est grisé : décocher les filtres IPv4/IPv6/Built-in dans la vue.

Ce que j’ai en prod (validé API + tests)

Section titled “Ce que j’ai en prod (validé API + tests)”
#NomActionDétail
1IoT DNSALLOWIoT → 192.168.20.2:53
2IoT to HAALLOWIoT → 192.168.50.204
3HA to IoTALLOW192.168.50.204 → IoT
4Admin labALLOWMain → Untrusted, tout
5DNS to Pi-holeALLOWMain → 192.168.20.2:53
6Main to ServersALLOWMain → Trusted, 445
7Lab to NASALLOWUntrusted → Trusted, 2049
8DNS labALLOWUntrusted → 192.168.50.2:53
9IoTBLOCKIoT → Trusted
10IoT to UntrustedBLOCKIoT → Untrusted

Les lignes 1–3 doivent rester avant 9–10 — sinon le BLOCK Untrusted avale aussi .204 (même anecdote qu’en tête d’article).

Autre erreur : HA to IoT en BLOCK au lieu d’ALLOW. MQTT IoT→HA peut passer avec allowReturnTraffic, mais dès que HA initie vers un device (certaines intégrations), le trafic part de .204 vers vlan 40 — ALLOW explicite, ou pas de règle du tout.

IoT to HA chez moi sans filtre port (tout vers .204). On pourrait limiter à 1883/8883 ; j’ai laissé plus large pour HA, à resserrer plus tard.

Test du weekend : intégrations IoT / MQTT OK après réordre et correction HA→IoT.

Deux familles de clés : cloud sur unifi.ui.com (Site Manager) vs locale sur la gateway (Settings → Integrations). Pour curl depuis le LAN, seule la locale marche sur https://192.168.50.1/proxy/network/.... Un 401 sur l’IP gateway = souvent la mauvaise clé.

Terminal window
export UNIFY_API_NETWORK_KEY="" # env locale, jamais dans Git
curl -sk -H "X-API-KEY: $UNIFY_API_NETWORK_KEY" \
"https://192.168.50.1/proxy/network/integration/v1/info"

Chez moi, un script lecture seule exporte VLANs, DNS DHCP par réseau, et policies USER_DEFINED — utile avant/après chaque changement firewall. L’idée se reproduit en quelques appels curl + jq sur l’API Integration.

WSL : LC_ALL=C.UTF-8 ou locale en_US.UTF-8 générée, sinon l’export peut planter sur des caractères bizarres.

SymptômeCause probable
401 sur gatewayClé cloud au lieu de clé locale
IoT ne joint pas HAIoT to HA sous BLOCK Untrusted
HA ne pilote pas IoTHA to IoT en BLOCK
IoT utilise .50.2 en DNSDHCP ou règle IoT DNS trop large
Règle « DNS » ouvre toutPas d’IP en destination, seulement Internal→Internal
Reorder griséFiltres actifs dans la vue Zones
Guest incohérentVlan id vs 3ᵉ octet (mon cas : .60)

Porte de sortie (avant d’ajouter du compute)

Section titled “Porte de sortie (avant d’ajouter du compute)”

Je ne lance pas de nouveau gros chantier (k3s, etc.) tant que ces points tiennent en test, pas seulement dans l’UI :

  • NFS depuis PVE (showmount -e 192.168.20.20, montages backups / media).
  • SMB depuis Windows (\\DS423, port 445).
  • Export API : ordre IoT ALLOW avant BLOCK, IoT DNS = .20.2:53 seul.
  • IoT : ping NAS en échec ; MQTT / HA OK.
  • Guest : isolationEnabled + clientIsolation Wi‑Fi, test téléphone.
  • Default vlan 1 : DHCP off.
  • Clé API locale en env, rien dans Git.

Accès distant (Tailscale, Cloudflare Access), IaC UniFi, Gravity Sync entre Pi-hole, et le détail d’un cluster k3s : autres guides. Ici l’objectif s’arrête quand le réseau est vérifiable et documenté.

  • LAN plat : simple au départ, ingérable quand NAS + lab + IoT + invités cohabitent.
  • VLAN sans firewall user = subnets décoratifs ; l’ordre des règles est critique (mon cas MQTT).
  • NFS et SMB vers le NAS : deux règles, pas un « allow NAS » fourre-tout.
  • IoT : DNS 20.2 + fallback public ; firewall explicite vers HA et Pi-hole seulement.
  • Export API régulier = la vérité ; l’UI ment parfois sur l’ordre affiché.