Code : MO-NET-006 | Version : 1.3 | Date : 20 septembre 2026 | Auteur : C. Legrand
Ce mode opératoire décrit le déploiement d'un contrôleur UniFi auto-hébergé sur l'infrastructure BTS SIO, nécessaire à l'administration des bornes Wi-Fi Ubiquiti UniFi U7 Pro Wall installées dans les salles S109, S110 et S111. Il couvre la chaîne complète : repérage des bornes sur le réseau, création de la stack Docker (application + base MongoDB) sur le serveur de conteneurs docker-srv, exposition de l'interface web via le reverse proxy Traefik, initialisation du contrôleur, mise en coffre du compte administrateur et adoption des bornes.
Une borne UniFi ne s'administre pas seule : elle exige une application de contrôle (UniFi Network) joignable en permanence. Le présent déploiement retient la voie conteneurisée demandée par l'équipe pédagogique, au moyen de l'image communautaire de référence linuxserver/unifi-network-application.
Retour d'expérience : la version 1.0 a été validée par le déploiement effectif le 01/09/2026 (UniFi Network Application 10.6.101) : stack opérationnelle sur le CT 200, interface publiée sous
https://unifi.docker.bts.sio, compte super-administrateur local en coffre et trois bornes découvertes automatiquement en attente d'adoption.
| Élément | Détail |
|---|---|
| Public | Administrateurs de l'infrastructure BTS SIO |
| Équipements gérés | 3 bornes Ubiquiti UniFi U7 Pro Wall (WiFi 7, PoE+, uplink 2,5 GbE) |
| Bornes déployées | BTSSIOI109 (10.0.230.2), BTSSIOI110 (10.0.230.3), BTSSIOI111 (10.0.230.5) — salles S109, S110, S111 |
| Plateforme cible | CT LXC 200 docker-srv (Debian 13, Docker 29) sur l'hyperviseur ProxMox 10.0.112.200 |
| Adresse du contrôleur | 10.0.112.228 (IP dédiée macvlan), UI https://unifi.docker.bts.sio |
| Accès requis | SSH vers ProxMox (alias bts-proxmox), droits pct exec sur le CT 200, coffre Vaultwarden de l'équipe |
| Durée estimée | 45 à 60 minutes (hors téléchargement des images, ≈ 2,3 Go) |
Ubiquiti propose depuis 2025 UniFi OS Server, présenté comme le nouveau standard de l'auto-hébergement. C'est la voie suggérée par l'enseignant ayant installé les bornes. Elle est écartée ici pour une raison bloquante : la documentation officielle précise qu'UniFi OS Server ne peut pas s'exécuter dans un conteneur Docker — « This is a complete solution that requires certain services to be run on the host ». L'installateur natif exige un Debian 13/Ubuntu 24.04 dédié, pilote lui-même des charges podman et monopolise plusieurs ports de l'hôte.
| A. Docker (retenue) | B. UniFi OS Server natif | |
|---|---|---|
| Logiciel | UniFi Network Application (branche classique 10.x) | UniFi OS Server 5.x (officiel) |
| Conteneur | Oui (image linuxserver + MongoDB) | Non (installateur hôte, podman piloté) |
| Emplacement | CT 200 docker-srv existant |
Nouveau CT/VM Debian 13 dédié |
| Fonctions UniFi OS | Non (Organizations, Site Magic absentes) | Oui |
| Pérennité | Branche « legacy » encore maintenue | Voie stratégique d'Ubiquiti |
Pour trois bornes en environnement pédagogique, les fonctions exclusives d'UniFi OS sont sans usage et la voie A s'intègre à l'outillage existant (Portainer, Traefik, sauvegardes vzdump du CT). La voie B reste une alternative documentée pour une évolution future.
Le contrôleur écoute sur les ports 8443 (UI), 8080 (inform), 3478/udp (STUN) et 10001/udp (découverte). Or le port 8080 de docker-srv est déjà occupé par Netbox, et la découverte de couche 2 traverse mal la translation de ports. La stack reçoit donc sa propre adresse IP 10.0.112.228 sur un réseau macvlan adossé à eth0 du CT : tous les ports du conteneur sont joignables directement, sans conflit ni NAT, et les bornes (même segment L2, réseau 10.0.0.0/16 plat) peuvent contacter l'inform.
Limite connue du macvlan : par conception, l'hôte (
docker-srv) ne peut pas joindre l'IP macvlan de ses propres conteneurs : les tests depuis le CT doivent être faits depuis un autre poste du LAN. Tous les autres équipements du réseau joignent10.0.112.228normalement.
Conformément à la convention de la plateforme, l'interface d'administration est publiée par le reverse proxy Traefik sous https://unifi.docker.bts.sio (certificat wildcard auto-signé *.docker.bts.sio, enregistrement DNS wildcard existant). Le backend UniFi n'exposant l'UI qu'en HTTPS auto-signé sur 8443, un transport insecureSkipVerify est ajouté à la configuration dynamique de Traefik. Le flux inform des bornes, lui, continue de viser directement http://10.0.112.228:8080/inform sans passer par le proxy.
Depuis le 20/09/2026, l'accès à l'UI est protégé à deux niveaux (chantier « UniFi derrière la porte Authentik », spec docs/superpowers/specs/2026-09-20-unifi-porte-authentik-design.md) :
unifi porte le middleware authentik@docker (forwardAuth, provider proxy unifi de l'outpost embarqué, policy « membre GG-AdminsPlateforme » — voir MO-PLT-025). L'accès à https://unifi.docker.bts.sio exige donc d'abord le compte AD, puis le login local du contrôleur (double saisie, limite produit Ubiquiti : pas de délégation d'authentification d'administration).10.0.112.228:8443 contourne par construction le reverse proxy (Traefik route par en-tête Host). Deux règles flottantes OPNsense la restreignent aux sources d'administration : PASS TCP 8443 depuis l'alias UniFi_Console_Admin_Sources (VLAN admin 10.0.112.0/24 + VPN collègues 10.10.30.0/24), puis BLOCK journalisé pour toute autre source. Les ports 8080 (inform) et 3478/udp (STUN) restent ouverts — les bornes en dépendent.Le compte local unique du contrôleur utilise le login admin@bts.sio (modifié le 20/09/2026 en CLI MongoDB, nom d'affichage Administrateur et mot de passe inchangés, item coffre à jour).
bts-proxmox) et droits pct exec sur le CT 20010.0.112.228 retenue, à référencer dans Netbox (MO-PLT-017)curl, nmap, jq et le client Bitwarden bwAucun secret ne doit figurer dans le fichier
docker-compose.yml: les mots de passe MongoDB sont générés aléatoirement et stockés dans/opt/docker/unifi/.env(chmod 600), sur le serveur uniquement. Le compte administrateur du contrôleur est, lui, conservé dans Vaultwarden.
Phase 1 Repérage des bornes sur le réseau (scan, OUI, DNS)
Phase 2 Création de la stack Docker sur docker-srv (.env, init-mongo.sh, compose)
Phase 3 Démarrage et validation de la stack
Phase 4 Exposition de l'interface via Traefik
Phase 5 Initialisation du contrôleur via l'API (compte, pays, fuseau, clôture)
Phase 6 Mise en coffre du compte administrateur (Vaultwarden)
Phase 7 Adoption des bornes
Phase 8 Vérification finale
nmap -sn -T4 10.0.230.0/23 -oG - | grep 'Status: Up'
ip neigh show dev enp45s0 | grep -v -E 'INCOMPLETE|FAILED'
Identifier les équipements Ubiquiti par leur OUI constructeur. Ici : trois adresses MAC en 58:d6:1f:xx (OUI 58:D6:1F = Ubiquiti), quasi séquentielles — signature d'un même lot de bornes neuves.
nmap -sV --version-light -p 22 10.0.230.2,3,5
Attendu : noms BTSSIOI109/110/111.bts.sio (une borne par salle) et service Dropbear sshd — le démon SSH embarqué des AP UniFi. Des machines Dell récentes (OUI E8:CF:83) présentes sur la même plage ne doivent pas être confondues avec les bornes.
10.0.230.2, 10.0.230.3, 10.0.230.5ssh bts-proxmox
pct exec 200 -- mkdir -p /opt/docker/unifi
Créer /opt/docker/unifi/.env avec des mots de passe générés (openssl rand -hex 20), droits 600 :
MONGO_ROOT_USER=root
MONGO_ROOT_PASSWORD=<mot de passe généré>
MONGO_USER=unifi
MONGO_PASS=<mot de passe généré>
MONGO_DBNAME=unifi
MONGO_AUTHSOURCE=admin
Déposer le script d'initialisation MongoDB /opt/docker/unifi/init-mongo.sh (contenu intégral en annexe B du PDF). L'application UniFi exige depuis la version 8.x une base MongoDB avec authentification RBAC : le script crée l'utilisateur applicatif avec les rôles clusterMonitor et dbOwner sur les bases unifi, unifi_stat, unifi_audit et unifi_restore. Il n'est exécuté qu'au premier démarrage de la base.
Déposer le fichier /opt/docker/unifi/docker-compose.yml (contenu intégral en annexe A du PDF). Points structurants :
unifi-macvlan (parent eth0, sous-réseau 10.0.0.0/16) : le conteneur unifi y reçoit l'IP fixe 10.0.112.228 ;unifi-internal (bridge interne) : seul lien entre unifi et mongo, jamais exposé ;mongo:7.0) : MongoDB ne supporte pas les montées de version majeure automatiques ;restart: unless-stopped sur les deux services, cohérent avec les autres stacks du serveur.pct exec 200 -- docker compose -f /opt/docker/unifi/docker-compose.yml up -d
pct exec 200 -- docker ps --filter name=unifi --format '{{.Names}} {{.Status}}'
pct exec 200 -- docker logs unifi 2>&1 | tail -5
Le premier tirage télécharge ≈ 2,3 Go d'images (5 à 15 minutes). Le premier démarrage de MongoDB exécute init-mongo.sh ; le premier démarrage d'UniFi génère le certificat auto-signé et initialise la base (2 à 4 minutes). Attendu : unifi et unifi-mongo Up, journal se terminant par [ls.io-init] done. sans exception Java.
Erreur typique au premier déploiement : si le journal affiche
IllegalArgumentException: No username is provided in the connection string, l'authentification MongoDB n'est pas en place. Reprendre le.envet le script d'init puis repartir d'un volume vierge :docker compose down, suppression demongo-data/etconfig/, puisup -d.
curl -kI https://10.0.112.228:8443/ renvoie 302curl http://10.0.112.228:8080/inform renvoie 400 (endpoint inform actif : le code 400 est la réponse normale à un GET)https://10.0.112.228:8443 affiche l'assistant UniFi/opt/docker/traefik/dynamic.yml :http:
serversTransports:
insecure:
insecureSkipVerify: true
Déclarer le provider fichier dans traefik.yml (bloc providers:) et monter le fichier dans le conteneur (./dynamic.yml:/etc/traefik/dynamic.yml:ro).
Composant partagé : Traefik porte tous les services web de la plateforme. Sauvegarder
traefik.ymletdocker-compose.ymlavant modification (cp fichier fichier.bak-AAAAMMJJ) et vérifier la non-régression des autres services après rechargement. La coupure du proxy pendant le rechargement est de quelques secondes.
Publier le contrôleur : compléter le service unifi (rattachement au réseau externe traefik-public + labels, dont server.scheme=https et serverstransport=insecure@file — annexe A du PDF). Aucun enregistrement DNS à créer : le wildcard *.docker.bts.sio résout déjà vers Traefik.
Recharger et recréer :
pct exec 200 -- docker compose -f /opt/docker/traefik/docker-compose.yml up -d
pct exec 200 -- docker compose -f /opt/docker/unifi/docker-compose.yml up -d
curl -k https://unifi.docker.bts.sio/ renvoie 302grafana, netbox, portainer, kuma.docker.bts.sio répondent normalementhttps://10.0.112.228:8443 reste fonctionnelL'assistant graphique peut être déroulé au navigateur, mais la phase est ici industrialisée par appels API (reproductible, sans poste graphique). Endpoints relevés dans le frontend de l'assistant (version 10.6.101).
Générer au préalable un mot de passe fort (openssl rand -hex 20) et le substituer à <MOT-DE-PASSE> dans les commandes ci-dessous ; il sera versé en coffre en phase 6.
curl -k -X POST https://10.0.112.228:8443/api/cmd/sitemgr \
-H 'Content-Type: application/json' \
-d @- <<'JSON'
{"cmd":"add-default-admin","name":"Administrateur","email":"<email-admin>","x_password":"<MOT-DE-PASSE>"}
JSON
250) et le fuseau (Europe/Paris) :curl -k -c /tmp/unifi.cookies -X POST \
https://10.0.112.228:8443/api/login -H 'Content-Type: application/json' \
-d @- <<'JSON'
{"username":"<email-admin>","password":"<MOT-DE-PASSE>","remember":false}
JSON
Relever le jeton CSRF dans le fichier de cookies (champ csrf_token) et le substituer à <JETON-CSRF> dans les appels d'écriture :
curl -k -b /tmp/unifi.cookies -X POST \
https://10.0.112.228:8443/api/set/setting/country \
-H "X-CSRF-Token: <JETON-CSRF>" -H 'Content-Type: application/json' \
-d @- <<'JSON'
{"code":"250"}
JSON
curl -k -b /tmp/unifi.cookies -X POST \
https://10.0.112.228:8443/api/set/setting/locale \
-H "X-CSRF-Token: <JETON-CSRF>" -H 'Content-Type: application/json' \
-d @- <<'JSON'
{"timezone":"Europe/Paris"}
JSON
curl -k -b /tmp/unifi.cookies -X POST \
https://10.0.112.228:8443/api/cmd/system \
-H "X-CSRF-Token: <JETON-CSRF>" -H 'Content-Type: application/json' \
-d @- <<'JSON'
{"cmd":"set-installed"}
JSON
Piège constaté en déploiement réel : tant que
set-installedn'a pas été appelé, l'URL/manage/account/loginredirige vers l'assistant (/setup/), dont l'écran « Sign In to Your UI Account » attend un compte cloud Ubiquiti (ui.com) — les identifiants locaux y sont rejetés alors qu'ils sont valides. Après clôture de l'assistant, la vraie page de connexion accepte le compte local. L'étape de liaison cloud est optionnelle et volontairement ignorée ici (contrôleur autonome, sans dépendance externe).

GET /api/self (avec session) retourne le compte, is_super: true, is_owner: truecurl -k https://unifi.docker.bts.sio/manage/account/login renvoie 200 (plus de redirection vers /setup/)https://unifi.docker.bts.sio (interface en français pour un navigateur français)Créer une entrée dans le coffre de l'équipe (MO-PLT-005), par exemple avec le client bw (substituer le mot de passe généré à MOT_DE_PASSE) :
bw get template item | jq --arg pw "MOT_DE_PASSE" '
.type=1
| .name="UniFi Network Controller (docker-srv)"
| .login.username="ADMIN_EMAIL"
| setpath(["login","password"]; $pw)
| .login.uris=[{"uri":"https://unifi.docker.bts.sio"}]
' | bw encode | bw create item
Renseigner en note : version de l'application, emplacement de la stack (/opt/docker/unifi, CT 200) et IP macvlan. Verrouiller le coffre après usage (bw lock) et supprimer tout fichier temporaire contenant le mot de passe.
Vérifier le paramètre Inform Host : Settings → System → Advanced, renseigner Inform Host = 10.0.112.228 et cocher Override. Ce réglage garantit que le contrôleur annonce aux équipements une adresse joignable (et non une IP interne au conteneur).
Adopter depuis l'inventaire : le contrôleur étant joignable en couche 2 par les bornes (même réseau 10.0.0.0/16), celles-ci apparaissent en attente dans UniFi Devices. Cliquer Adopt sur chacune (1 à 3 minutes, la borne redémarre).

ubnt/ubnt) :ssh ubnt@10.0.230.2
set-inform http://10.0.112.228:8080/inform
Après adoption, les identifiants SSH des bornes sont remplacés par ceux définis dans Settings → System → Device SSH Authentication.

https://unifi.docker.bts.sio (porte Authentik puis login local, voir « Protection de l'accès ») et https://10.0.112.228:8443 (direct, restreint à l'alias UniFi_Console_Admin_Sources depuis le 20/09/2026)docker restart unifi unifi-mongo, services Up et UI de nouveau accessible10.0.112.228 référencée dans Netbox (MO-PLT-017) et dans ACCES_INFRASTRUCTURE.mdSauvegardes. Deux niveaux complémentaires : la sauvegarde applicative UniFi (Settings → System → Backup, fichiers .unf dans /opt/docker/unifi/config/data/backup/, à exporter vers le NAS) et la sauvegarde infrastructure du CT 200 par les jobs vzdump de l'hyperviseur (MO-PLT-016).
Mises à jour.
pct exec 200 -- docker compose -f /opt/docker/unifi/docker-compose.yml pull
pct exec 200 -- docker compose -f /opt/docker/unifi/docker-compose.yml up -d
L'image applicative suit l'étiquette latest (cohérent avec les autres stacks) ; l'image MongoDB reste figée en 7.0. Avant toute mise à jour applicative, déclencher une sauvegarde depuis l'UI.
Restauration sur une stack neuve. Déployer la stack (phases 2 et 3), ouvrir l'UI et choisir Restore from backup dans l'assistant. Les bornes se reconnectent d'elles-mêmes dès que l'adresse inform (10.0.112.228:8080) redevient joignable — l'IP macvlan doit donc être conservée.
| Problème | Solution |
|---|---|
unifi redémarre en boucle, « No username is provided in the connection string » |
Authentification MongoDB absente. Reprendre init-mongo.sh et .env, repartir d'un volume vierge (phase 3). |
502 Bad Gateway sur unifi.docker.bts.sio |
Backend HTTPS auto-signé : vérifier le label server.scheme=https et le transport insecure@file (dynamic.yml monté, provider file déclaré dans traefik.yml). |
| Login refusé sur l'écran « UI Account » | Cet écran attend un compte cloud Ubiquiti, pas le compte local. Si l'URL de connexion redirige vers /setup/, l'assistant n'est pas clôturé : appeler set-installed (phase 5). |
| Une borne n'apparaît pas dans l'inventaire | Vérifier Inform Host = 10.0.112.228 (case Override), puis set-inform http://10.0.112.228:8080/inform en SSH sur la borne. |
Le CT n'arrive pas à tester 10.0.112.228 |
Limite macvlan : l'hôte ne joint pas l'IP macvlan de ses conteneurs. Tester depuis un autre poste du LAN. |
| Interface lente, conteneur limité mémoire | MEM_LIMIT (Mo) borne le tas Java (2048 par défaut). Surveiller la mémoire du CT 200 (8 Go partagés). |
docker compose -f /opt/docker/unifi/docker-compose.yml down puis rm -rf /opt/docker/unifi.file de traefik.yml et le montage dynamic.yml, ou restaurer les sauvegardes *.bak-AAAAMMJJ de la phase 4, puis recharger Traefik.10.0.112.228 dans Netbox et retirer l'entrée du coffre si le contrôleur n'est pas redéployé.