✨ Operation Northstar
Operation Northstar est la refonte complète de mon homelab : migration ZeroTier vers Headscale, mise en place d’un edge centralisé avec Consul, développement d’un agent de découverte pour exposer automatiquement les services, et suppression d’une dépendance circulaire Auth/SSO ↔ VPN ↔ Edge. Un retour d’expérience technique, brut, pédagogique et documenté.
Operation Northstar
Migration réseau & edge vers une architecture unifiée, sécurisée et (beaucoup) plus lisible.
Auteur : EL OUAZIZI Walid
Début : 21/02/2026
Durée initialement prévue : 4–5 jours
Assistant : OpenClaw — PoC, automatisation, et communication via une Maintenance API
TL;DR
Mon homelab est passé d’un empilement “ça marche depuis longtemps” à une archi où :
- le mesh n’est plus un SaaS limité (ZeroTier → Headscale self-hosted, overlay
100.64.0.0/10) - l’exposition publique est centralisée sur une edge dédiée
- l’edge ne “devine” plus les services : elle consomme un catalogue (Consul)
- les nœuds publient automatiquement leurs routes via un agent de découverte (Traefik → Consul)
- le control-plane (Auth/SSO, VPN) est traité comme critique et ne doit plus dépendre d’un flux fragile
Et au milieu : un incident de migration qui révèle ce que mon infra était vraiment :
une dépendance circulaire Authentik ↔ VPN ↔ Edge.
1) Le point de départ : “WalidLab” et la dette invisible
À la base, je n’avais qu’un seul serveur : WalidLab.
Puis j’ai ajouté des services, des nœuds, des reverse proxies, des tunnels… jusqu’à atteindre un état très commun en homelab :
Tout fonctionne, mais personne (moi y compris) n’est capable de décrire précisément les flux sans rouvrir 12 configs.
Le problème n’était pas “un hub”.
Le problème était l’empilement et les dépendances implicites.
2) Pourquoi Northstar ?
2.1 Sortir du mesh SaaS (ZeroTier)
ZeroTier fait le job, mais :
- contrôleur cloud (SaaS)
- limitations de plan
- gouvernance ACL / flux moins “à moi”
- envie de self-host, d’apprendre et de maîtriser
Je voulais un mesh overlay self-hosted, avec une gouvernance claire.
Choix : Headscale (control-plane self-hosted pour clients Tailscale).
2.2 Clarifier l’edge
Je voulais un edge dont le rôle est uniquement :
- terminer le tunnel public
- router proprement
- être documentable
Oui, ça crée un SPoF.
Mais c’est un SPoF assumé et simple (et, dans mon contexte, acceptable).
2.3 Passer d’un routage artisanal à une exposition déclarative
Le vrai besoin : arrêter de “câbler des routes” à la main.
Je voulais un pipeline net :
1) Un service apparaît sur un nœud
2) Il est découvert/enregistré avec des métadonnées
3) L’edge le publie automatiquement
3) Le plan initial (et les vraies étapes)
Le plan tel que je l’ai posé au départ :
- Migration du mesh : ZeroTier → Headscale
- Migration / refonte DNS (zones dnsmasq → MagicDNS / CoreDNS)
- Centralisation des edges (edge unifiée)
- Mise en place / convergence cluster (Swarm était dans le scope)
- Sécurisation + audit post-maintenance
- Analyse sécurité + doc
En pratique, la réalité a été plus “vivante” (et plus intéressante).
4) La couche “Ops” : Maintenance API + Worker Cloudflare (et OpenClaw)
OpenClaw a géré une API de maintenance exposée via un Worker Cloudflare.
But : garder un statut public propre, et éviter le “je spam des messages incohérents”.
Ça a été utile… et ça a aussi causé un des blocages les plus débiles de l’opération.
Oui : mon outil de maintenance a brièvement cassé mon control-plane réseau. Ironie parfaite.
5) Migration VPN : ZeroTier → Headscale (les pièges qui font mal)
5.1 Premier mur : “Tailscale unreachable” / OIDC off / edge off
À un moment, je coupe les edges ⇒ alertes.
Je check “tailscale reachable” ⇒ échec.
Cause (au final) :
- domaine non autorisé (OIDC)
- edge VPS off
- OIDC off
Solution :
- rallumer les edges
- autoriser les domaines nécessaires
- reboot headscale, OIDC et traefik
Leçon : en migration, si tu coupes trop de “supports” à la fois, tu te fabriques un labyrinthe.
5.2 Deuxième mur : OIDC bizarre (HTTPS KO, HTTP OK)
Symptôme :
- login OIDC impossible en HTTPS, mais possible en HTTP
- interface OK, mais toutes les routes
/apirenvoient 401
Après beaucoup trop de tests : le coupable était… la Maintenance API.
5.3 Le bug “maintenance” qui casse le réseau (WebSocket intercepté)
Résumé pédagogique (le plus proche possible de ce que j’ai observé) :
- le client se connecte au control-plane via WebSocket
- le handshake WebSocket passait par la couche “maintenance” (Worker CF)
- et pour une raison de forwarding / compatibilité, le Worker ne transmettait pas correctement ce handshake
Résultat : mesh “capricieux”, comportements non déterministes.
Contournement : route “no-script / bypass” sur une zone dédiée.
Leçon : un proxy intermédiaire peut casser un protocole à bas bruit (et te faire perdre des heures).
5.4 Troisième mur : “tout est connecté” mais rien ne ping
Autre piège classique :
- les nœuds apparaissent connectés
- DERP OK
- mais ils ne se joignent pas
Cause : ACL.
Fatigue + ACL = temps perdu garanti.
Leçon : un réseau overlay peut être “UP” tout en étant inutilisable si les politiques sont mal modélisées.
6) DNS : le pragmatisme avant la pureté
Pendant la transition :
- config dnsmasq temporaire pour des résolutions liées à l’overlay (
100.64.0.0/10) - réflexion “MagicDNS / CoreDNS” pour converger vers une résolution stable sans dépendance locale
Point marquant : après migration DNS, j’ai dû ajuster le démon Docker pour qu’il résolve via le DNS Tailscale (100.100.100.100).
Sans ça, Docker ne récupérait pas les bons paramètres DNS (à investiguer plus tard).
Leçon : DNS et runtimes (Docker) ont leurs propres idées sur “d’où vient la résolution”. Ne pas présumer que tout suit automatiquement.
7) Le pivot de l’opération : edge unifiée + service discovery
Je voulais arrêter le multiproxy “au fil de l’eau”.
Et j’ai voulu centraliser l’edge de façon propre.
7.1 L’idée cible
- Une edge (Traefik)
- Un réseau overlay cohérent
- Un catalogue (Consul) comme source de vérité
- Les services “s’enregistrent” dans Consul, l’edge consomme et publie
7.2 Le premier mur : Consul “KO / nul / pas adapté” (au début)
Dans le déroulé, il y a eu un moment “images pushant docker ⇒ Consul KO ou nul et peu fonctionnel”.
En clair : naïvement, ce que je voulais faire n’était pas si simple avec les outils “classiques” à disposition.
C’est là que OpenClaw intervient vraiment : il ne m’a pas “expliqué”, il a itéré des PoC.
8) L’évolution des PoC : Registrator → agent custom → discovery v2
8.1 Tentative Registrator (et pourquoi ça n’a pas suffi)
Premiers essais : “agent Registrator” pour enregistrer des services dans Consul.
Problèmes rencontrés (d’après le status) : image legacy non supportée, alternatives à trouver, access réseau pas toujours dispo.
C’était un bon déclencheur : je voulais quelque chose de moderne et stable.
8.2 Le vrai breakthrough : agent custom
Le moment clé : un PoC où un container est enregistré dans Consul sans port publié sur l’hôte.
L’agent est capable d’enregistrer :
- une IP sur un réseau interne
- un port déduit
- et surtout : des tags Traefik namespacés pour que l’edge consomme automatiquement l’entrée.
C’est à ce moment-là que Northstar passe de “migration infra” à “architecture unifiée”.
8.3 Discovery v2 : événementiel, résilience, cache local, push delta
La v2 de l’agent (toujours côté status) :
- mode événementiel temps réel
- support multi-router / multi-service
- health checks Consul intégrés
- résilience : cache local + push delta au retour du catalogue
- documentation technique (variables, debug) côté docs
En clair : on n’est plus sur un script “best effort”.
On a un composant prod-ready dans l’esprit.
9) Architecture : avant / après (ASCII, mais utile)
🔴 Avant
Cloudflare DNS
│
CF Tunnel
│
WalidLab (services + reverse proxy + edge “historique”)
│
ZeroTier (mesh SaaS, contrôleur cloud)
│
Autres nœuds (services + parfois leur Traefik)
Problèmes principaux :
- edge pas assez isolée
- exposition “au fil de l’eau”
- dépendances implicites
- pas de source de vérité “catalogue”
🟢 Après (cible Northstar)
Cloudflare DNS
│
CF Tunnel
│
EDGE NODE (Traefik + Consul + Cloudflared)
│
Headscale overlay (100.64.0.0/10)
│
Nœuds applicatifs (Traefik local + agent discovery)
Philosophie :
- l’edge consomme Consul Catalog (provider)
- chaque nœud publie ses routers/middlewares via l’agent
- l’edge reste simple et documentable
- le mesh est self-hosted, gouverné par ACL
10) L’incident “serpent qui se mord la queue” (Tunnel / Authentik / Headscale)
C’est LE moment pédagogique.
10.1 Le déclencheur
Je provisionne la nouvelle VM edge de A à Z : tout OK.
Je commence à migrer les records : au début, tout roule, les sites publics fonctionnent.
Puis, pendant la migration du tunnel vers la nouvelle edge :
- Authentik s’arrête
- en cascade, Headscale se crash/instabilise
- perte de connectivité de certaines machines
- donc impossibilité de redeployer proprement…
En gros : je viens de créer un deadlock.
10.2 Pourquoi ça arrive
Parce que je suis tombé sur une dépendance circulaire typique :
- l’accès à Authentik dépendait du routage edge
- le routage edge dépendait du mesh (overlay)
- le mesh dépendait (directement ou indirectement) d’Authentik
Ce n’était pas visible avant, parce que le flux “historique” le masquait.
La migration a révélé la vraie topologie.
10.3 Le contournement qui sauve
Heureusement :
la machine qui pousse actuellement sur l’edge était en LAN avec la machine qui host Authentik.
Donc j’ai pu bypass le VPN :
- déclaration de l’IP LAN à la place
- Authentik revient
- Headscale revient
- control-plane rétabli
Leçon : toujours un chemin hors-overlay / hors-tunnel = différence entre “incident gérable” et “enfermement total”.
11) La correction structurelle : casser la dépendance, pas juste réparer
J’ai fait deux choses :
1) stabiliser le routage (dupliquer, basculer proprement, retirer l’ancien flux)
2) rendre Authentik accessible en permanence, sans dépendre de l’edge dont le routage dépend du VPN
11.1 Décision : “control-plane” doit être exposé direct
Même philosophie que Headscale :
- Headscale est exposé en direct (nécessaire)
- Authentik doit être “break-glass friendly”
11.2 Mise en place finale
J’ai figé :
authentik.mazone → Cloudflare Tunnel → socat (HTTPS) → Traefik Node B
Ainsi :
- Auth/SSO reste accessible même si l’edge unifiée a un souci
- je ne recrée plus la boucle Auth ↔ VPN ↔ Edge
12) Optimisations : réduire l’overhead inutile
Deux points de perf / simplicité :
- keep-alive sur les connexions vers les reverse proxies (réduction overhead TCP)
- passer certains flux internes en HTTP (quand l’overlay est déjà chiffré) pour éviter des handshakes TLS multiples
Ce n’est pas un dogme. C’est du pragmatisme : sécurité globale + complexité maîtrisée.
13) Checklist de migration (si je devais recommencer demain)
Phase 1 — Préparer sans toucher au prod
- edge prête mais non “authoritative”
- tunnel test séparé
- Consul up + healthchecks
- agent PoC validé sur VM de test
- Authentik accessible hors-overlay (dès le début)
Phase 2 — Mesh
- migration hôte par hôte
- ACL minimal viable puis durcissement
- tests node-to-node (pas juste “connected”)
- validation DERP / latence
Phase 3 — Discovery / exposition
- activer agent sur 1 nœud applicatif
- vérifier entrée Consul + tags Traefik
- vérifier que l’edge route correctement
- tester panne Consul (cache + push delta au retour)
Phase 4 — Bascule DNS / tunnel
- bascule progressive
- monitor Auth/SSO et VPN en priorité
- garder un bypass prêt (LAN / direct route)
Phase 5 — Post-migration
- audit ACL + firewall
- documentation des flux
- observabilité minimale (checks + logs)
- nettoyage des anciens chemins
14) Leçons (celles que je garde vraiment)
1) Une migration ne casse pas ton infra : elle révèle ce qu’elle est.
2) “Connected” ne veut rien dire si les ACL interdisent le data-plane.
3) Un Worker Cloudflare peut casser un handshake WebSocket.
4) DNS ne répare pas une absence de connectivité.
5) Le control-plane (VPN, Auth) doit rester accessible sans dépendre de l’edge.
15) Ce qu’il reste à faire
- Migrer le Traefik VPS
- Mettre un Traefik sur le RPI (services intranet)
- Harmoniser les edges internes
- Audit sécurité post-maintenance
- Finaliser la doc (schémas + conventions de tags + runbook “break glass”)
Conclusion
Northstar n’était pas un “changement de tunnel”.
C’était une correction de philosophie :
- séparation des responsabilités
- edge unifiée + catalog
- discovery automatisée
- control-plane rendu robuste
- dépendances implicites → flux intentionnels
Mon homelab n’est pas parfait.
Mais maintenant, je peux expliquer ce qu’il fait — et surtout pourquoi.