# Deployeur studioE5 — Onboarding d’un nouvel établissement ## Objectif Ce document décrit le fonctionnement du **deployeur studioE5**, c’est-à-dire l’application / l’outil qui provisionne et configure un nouvel environnement client (un établissement) prêt à accueillir l’application studioE5. L’application studioE5 elle-même (agent, VPN on-demand, resolver, Caddy, Headscale, etc.) est documentée dans `SUIVI_VPN_ONDEMAND.md`. Le deployeur est l’outil qui **déploie** cette application sur un VPS dédié au client. --- ## Public cible - Équipe produit / développement du deployeur - Équipe ops / déploiement - Référents techniques du client A --- ## Glossaire | Terme | Définition | |-------|------------| | **Deployeur** | Application qui provisionne un VPS, déploie la stack studioE5 et configure le DNS/certificats pour un nouvel établissement. | | **Hub central** | Dashboard superadmin studioE5 qui orchestre les déploiements et la gestion multi-clients. | | **Établissement** | Entité client (école, lycée, université, entreprise). | | **Tag établissement** | Slug unique et court identifiant l’établissement dans les URLs et le DNS. | | **Domaine géré** | Sous-domaine fourni par studioE5 : `*.tag.edudeploy.com`. | | **Domaine propre** | Domaine détenu par l’établissement : `*.tag.monetablissement.fr`. | | **Application studioE5** | Stack complète déployée sur le VPS : `server`, `resolver`, `resolver-vpn`, `caddy`, `headscale`, `postgres`, etc. | | **Agent générique** | Binaire agent unique, capable de se connecter à n’importe quel serveur studioE5 via résolution d’URL à l’activation. | --- ## Architecture : deployeur vs application studioE5 ``` ┌─────────────────────────────────────────────────────────────┐ │ Hub central studioE5 │ │ (superadmin, gestion des établissements, monitoring) │ └───────────────────────┬─────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Deployeur studioE5 │ │ (provisionning VPS, DNS, certificats, déploiement stack) │ └───────────────────────┬─────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Application studioE5 (un par client) │ │ Caddy — Resolver — Resolver-VPN — Headscale — Server — DB │ │ ▲ │ │ │ WebSocket / VPN on-demand │ │ ▼ │ │ Agent élève (Windows/Linux) │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Flux d’onboarding par le deployeur (vue d’ensemble) ``` Création de l’établissement dans le hub ↓ Choix du domaine (géré ou propre) ↓ Génération du tag établissement ↓ Provisionning du VPS ↓ Configuration DNS wildcard ↓ Génération du certificat wildcard ↓ Déploiement de la stack studioE5 (Docker Compose) ↓ Initialisation de Headscale et création des clés ↓ Création du compte administrateur de l’établissement ↓ Génération des codes d’activation ↓ Build et mise à disposition de l’agent dédié ↓ Activation de l’agent par un élève ↓ Création d’une première instance (validation du déploiement) ``` --- ## 1. Création de l’établissement dans le hub Le superadmin crée un nouvel établissement dans le hub central. Données minimales : - Nom officiel - Type d’établissement (école, lycée, université, entreprise) - Pays / fuseau horaire - Contact administrateur - Choix du mode de domaine (`managed` ou `custom`) --- ## 2. Choix du domaine ### Option A — Domaine géré par studioE5 (MVP) Le deployeur crée automatiquement un sous-domaine du domaine maître : ``` *.tag.edudeploy.com ``` Le hub gère le DNS chez le registrar studioE5 (actuellement Infomaniak). ### Option B — Domaine propre de l’établissement (évolution) L’établissement fournit son propre domaine : ``` *.tag.monetablissement.fr ``` Prérequis : - Le client pointe son DNS wildcard vers l’IP du VPS provisionné. - Le deployeur dispose d’un token API du registrar du client pour le challenge DNS-01. --- ## 3. Génération du tag établissement Le tag est un slug court, unique au niveau du hub, utilisé dans les URLs et le DNS. ### Règles - Uniquement `[a-z0-9-]` - Pas de tiret au début ni à la fin - Longueur conseillée : 2 à 20 caractères - Vérification d’unicité en base ### Exemples | Nom d’établissement | Tag | |---------------------|-----| | Lycée Jules Ferry | `ljf` | | Institut Supérieur du Digital | `isd` | | École Notre-Dame | `end` | ### Gestion des collisions - `ljf` → `ljf-2`, `ljf-3`, etc. --- ## 4. Provisionning du VPS Le deployeur provisionne un VPS dédié pour l’établissement. ### Prérequis sur le VPS vierge - OS Linux (Ubuntu LTS recommandé) - Docker + Docker Compose installés - Accès SSH avec clé - Ports ouverts : 22, 80, 443 ### Actions automatisées par le deployeur 1. Installation de Docker et Docker Compose si absent. 2. Création de la structure de dossiers (`/opt/studioe5-/`). 3. Génération des secrets (`.env`) : - `INTERNAL_API_KEY` - `HEADSCALE_API_KEY` - `HEADSCALE_AUTH_KEY` (réutilisable, taguée `tag:student-agent`) - `HEADSCALE_RESOLVER_AUTH_KEY` - `INFOMANIAK_API_TOKEN` (si domaine géré) - `NEXTAUTH_SECRET`, `DATABASE_URL`, etc. 4. Récupération des images Docker depuis le registry privé (ou build sur place en attendant). 5. Génération des fichiers de configuration (`Caddyfile`, `docker-compose.yml`, `headscale/config.yaml`, `headscale/acl_policy.hujson`). --- ## 5. Configuration DNS wildcard ### Domaine géré Le deployeur appelle l’API du registrar pour créer : ```dns *.tag.edudeploy.com A ``` ### Domaine propre Le deployeur vérifie que l’enregistrement existe : ```dns *.tag.monetablissement.fr A ``` --- ## 6. Certificat wildcard ### Principe Un seul certificat wildcard couvre toutes les instances futures de l’établissement. ### Mise en œuvre avec Caddy Le deployeur génère le `Caddyfile` : ```caddy *.tag.edudeploy.com { tls { dns infomaniak {env.INFOMANIAK_API_TOKEN} } reverse_proxy resolver:2020 { header_up Host {host} } } ``` Pour un domaine propre, le provider DNS est celui du client. ### Renouvellement Géré automatiquement par Caddy. --- ## 7. Déploiement de la stack studioE5 Le deployeur lance la stack Docker Compose complète : ```bash cd /opt/studioe5- docker compose up -d ``` Services déployés : - `server` : API + WebSocket + UI Next.js - `resolver` : reverse proxy interne vers les instances - `resolver-vpn` : sidecar Tailscale dans le netns du resolver - `caddy` : reverse proxy public + TLS - `headscale` : contrôleur Tailscale - `postgres` : base de données --- ## 8. Initialisation de Headscale Le deployeur initialise Headscale et crée les clés nécessaires : ```bash # Création de l’utilisateur dédié au resolver docker compose exec headscale headscale users create resolver # Création de la clé pré-auth réutilisable pour les agents docker compose exec headscale headscale preauthkeys create \ --user studioe5 \ --reusable \ --tags tag:student-agent \ -e 87600h # Création de la clé pré-auth pour le resolver docker compose exec headscale headscale preauthkeys create \ --user resolver \ --tags tag:resolver \ -e 87600h # Création d’une clé API Headscale valable 10 ans docker compose exec headscale headscale apikeys create -e 87600h ``` Ces secrets sont stockés dans le `.env` du serveur. --- ## 9. Création du compte administrateur de l’établissement Une fois la stack déployée, le deployeur (ou le hub) crée le premier compte administrateur de l’établissement via l’API du serveur nouvellement déployé. Rôles : - `admin` : gestion des élèves, instances, agents. - `teacher` : gestion limitée à certaines classes/groupes. - `superadmin` (studioE5) : accès transverse. L’administrateur reçoit un lien d’activation sécurisé. --- ## 10. Génération des codes d’activation Le deployeur configure le serveur pour permettre la génération de codes d’activation. ### Règles de sécurité (implémentées côté application studioE5) - Génération avec `crypto.randomBytes` - Alphabet sans ambiguïté : `ABCDEFGHJKLMNPQRSTUVWXYZ23456789` - 6 caractères - Expiration après 60 minutes - Invalidation après usage - Rate-limiting : 5 tentatives par code / 5 tentatives par `nodeId` sur 15 minutes ### Flux 1. L’administrateur génère un code pour un élève. 2. L’élève saisit le code dans l’agent. 3. Le serveur valide et renvoie : - l’identité de l’élève - l’URL Headscale - une clé pré-auth Headscale éphémère 4. L’agent démarre automatiquement le VPN. --- ## 11. Build et mise à disposition de l’agent ### Principe L’agent est un binaire générique, mais il doit être capable de se connecter au bon serveur. Le deployeur génère un agent pré-configuré ou un installeur qui embarque l’URL du serveur de l’établissement. ### Build ```bash cd /opt/studioe5-/agent ./download-tailscale-bins.sh 1.98.4 ./build.sh ``` Artifacts générés : - `studioE5-agent-vX.Y.Z-windows.zip` - `studioE5-agent-vX.Y.Z.exe` - `studioE5-agent-vX.Y.Z` (Linux) ### Mise à disposition Les fichiers sont servis par Caddy depuis `server/public/agent/` : ``` https://tag.edudeploy.com/studioE5-agent-vX.Y.Z-windows.zip ``` --- ## 12. Activation de l’agent ### Activation zéro-config 1. L’élève télécharge l’agent depuis l’URL de l’établissement. 2. Il extrait l’archive et lance `studioE5-agent.exe`. 3. Il ouvre `http://localhost:7070`. 4. Il saisit le code d’activation à 6 caractères. 5. L’agent contacte le serveur, récupère la configuration et démarre le VPN. > Les détails techniques du VPN on-demand (named pipes Windows, logs, ACL, tokens, clés éphémères) sont documentés dans `SUIVI_VPN_ONDEMAND.md`. --- ## 13. Création d’une instance et construction de l’URL (validation) Le deployeur ou l’administrateur crée une première instance pour valider le déploiement. ### Format d’URL ``` -.. ``` Exemple : ``` wp-jd47.ljf.edudeploy.com ``` Avec : - `wp` : type d’application - `jd` : initiales de l’élève - `47` : identifiant court unique - `ljf` : tag de l’établissement - `edudeploy.com` : domaine de base ### Mapping type d’application → préfixe | Application | Préfixe | |-------------|---------| | WordPress | `wp` | | PrestaShop | `ps` | | Moodle | `mdl` | | Nextcloud | `nc` | ### Protection de l’identité - L’URL ne contient pas le nom complet de l’élève. - Seules les initiales + un identifiant court opaque sont exposées. --- ## 14. Modèles de données du deployeur ### Table / modèle `Organization` (établissement dans le hub) ```json { "id": "uuid", "name": "Lycée Jules Ferry", "tag": "ljf", "domainMode": "managed", "baseDomain": "edudeploy.com", "adminEmail": "admin@ljf.fr", "status": "active", "createdAt": "2026-06-25T17:28:07Z" } ``` ### Table / modèle `Deployment` (déploiement sur un VPS) ```json { "id": "uuid", "organizationId": "uuid", "serverIp": "203.0.113.10", "serverHostname": "ljf.studioe5.edudeploy.com", "wildcardDnsConfigured": true, "wildcardCertificateReady": true, "dnsProvider": "infomaniak", "dnsProviderTokenRef": "env:INFOMANIAK_TOKEN_LJF", "headscaleApiKeyRef": "env:HEADSCALE_API_KEY_LJF", "status": "ready", "deployedAt": "2026-06-25T17:28:07Z" } ``` ### Table / modèle `Student` (dans l’application studioE5 déployée) ```json { "id": "uuid", "organizationId": "uuid", "firstName": "Jean", "lastName": "Dupont", "initials": "jd", "activationCode": "AB3D9F", "activationCodeExpiresAt": "2026-06-25T18:28:07Z", "nodeId": "vps-8fc665eb", "nodeToken": "..." } ``` ### Table / modèle `Instance` (dans l’application studioE5 déployée) ```json { "id": "cmqqgrur20001lw67t2bdgzkg", "organizationId": "uuid", "studentId": "uuid", "nodeId": "vps-8fc665eb", "templateId": "wordpress-wordpress-latest", "applicationPrefix": "wp", "shortId": "47", "subdomain": "wp-jd47", "fqdn": "wp-jd47.ljf.edudeploy.com", "port": 8001, "status": "running" } ``` --- ## 15. Sécurité et RGPD ### Protection de l’identité de l’élève - L’URL publique ne contient pas le nom complet de l’élève. - Seules les initiales + un identifiant court opaque sont exposées. ### Isolation réseau - Les agents élèves ne peuvent pas communiquer entre eux (ACL Headscale). - Le resolver est le seul service autorisé à joindre les agents sur leurs ports d’instance. ### Authentification - Token unique par agent (`node.token`). - Clé API interne pour les endpoints serveur → agent. - Sessions NextAuth sur les routes API métier. ### Clés pré-auth Headscale - Éphémères, à usage unique, 15 minutes d’expiration. - Non persistées côté agent. --- ## 16. Checklist de validation du deployeur À l’issue d’un onboarding, les points suivants doivent être validés : - [ ] L’établissement est créé dans le hub avec un tag unique. - [ ] Le VPS est provisionné et accessible en SSH. - [ ] Docker et Docker Compose sont installés. - [ ] Le DNS wildcard est résolu (`*.tag.edudeploy.com` → IP du VPS). - [ ] Le certificat wildcard est obtenu et valide. - [ ] La stack studioE5 est démarrée (`docker compose ps`). - [ ] Headscale est initialisé avec les utilisateurs et clés nécessaires. - [ ] Le compte administrateur de l’établissement est créé. - [ ] Un code d’activation peut être généré pour un élève. - [ ] L’agent est buildé et téléchargeable depuis le serveur de l’établissement. - [ ] L’agent s’active avec le code zéro-config. - [ ] Une instance peut être créée et son URL est accessible en HTTPS. - [ ] Deux instances différentes reçoivent des URL uniques. - [ ] Le flux HTTPS complet retourne bien HTTP 200. --- ## 17. Roadmap du deployeur ### Court terme (MVP) - Déploiement manuel ou semi-automatisé d’un nouvel établissement sur un VPS. - Domaine géré par studioE5 uniquement. - Build des images sur le VPS cible. - Agent avec URL serveur hardcodée ou fournie à l’activation. ### Moyen terme - **Agent générique** : déterminer l’URL serveur cible à l’activation (code structuré, hub de résolution, ou champ URL). - **Script de provisionning** : installation Docker, déploiement stack, génération secrets, DNS wildcard. - **Registry d’images privé** : builder une fois, déployer partout. - Support de domaines propres à l’établissement. - Support multi-registrar DNS. ### Long terme - **Hub central multi-clients** : dashboard superadmin, gestion des versions, logs distants. - **Mises à jour à distance** : pousser une nouvelle version du serveur et de l’agent sur tous les déploiements. - **Monitoring / support** : alertes serveur down, certificat expiré, agent hors ligne. - **Tests automatisés** : validation du flux activation → VPN → instance → HTTPS public à chaque déploiement. - **Console/log intégré et barre de progression** dans l’agent. - Génération automatique de codes d’activation par import CSV.