# Suivi – VPN on-demand studioE5 (client A) ## ✅ Ce qui fonctionne 1. **Agent standalone (mode console / systray)** - Exécutable : `agent/studioE5-agent` - Config lu depuis `/studioE5-config.json` - Mode console : `-no-tray` 2. **VPN on-demand dans l'agent** - L’agent ne démarre plus Tailscale au boot. - Le VPN se lance automatiquement à la création/démarrage d’une instance, ou sur commande serveur. - Implémentation basée sur les binaires `tailscaled` + `tailscale up` (pas `tsnet`, car `tsnet` ne loguait pas automatiquement avec une authkey sur un state vierge). 3. **Commandes serveur → agent** - Endpoint de test : `POST /api/internal/send-to-node` - Actions supportées : `start_vpn`, `stop_vpn`, `start`, `stop`, `reset`, `delete`. 4. **Resolver/serveur dans le tailnet studioe5** - Service `resolver-vpn` (conteneur Tailscale) partage le netns du `resolver`. - Le resolver peut joindre les IPs Tailscale des nodes (`ping 100.64.0.x` OK). 5. **Instance WordPress démarrée avec succès** - Le resolver a renvoyé une 302 WordPress via `http://resolver:2020/`. 6. **Activation zéro-config de l’agent (modèle commercialisable)** - L’agent démarre sans `headscale_url` ni `headscale_auth_key`. - L’utilisateur entre seulement un code d’activation. - Le serveur envoie la config Headscale, l’agent la sauvegarde et démarre le VPN automatiquement. ## ✅ Blocage levé **Rate limit Let’s Encrypt pour `edudeploy.com` est levé.** Le 2026-06-23 vers 09:35 UTC, Caddy a pu obtenir un certificat Let’s Encrypt pour `test-wp-001.studioe5.edudeploy.com` : ``` tls.obtain: certificate obtained successfully identifier=test-wp-001.studioe5.edudeploy.com issuer=acme-v02.api.letsencrypt.org-directory ``` Le flux complet HTTPS public est désormais validé : ```bash curl -sS -I -L https://test-wp-001.studioe5.edudeploy.com/ # => HTTP/2 302 -> HTTP/2 200 (WordPress install.php) ``` Le DNS wildcard `*.studioe5.edudeploy.com` est en place. Caddy utilise toujours `tls { on_demand }` et émet un certificat par sous-domaine d’instance. ## 🎯 Validation du flux HTTPS public Le 2026-06-23 09:39 UTC, le flux complet a été validé : ```text Client (HTTPS) → Caddy (:443) → resolver (:2020) → Tailnet (100.64.0.8) → agent → WordPress (:8001) ``` Résultat : ```bash $ curl -sS -I -L https://test-wp-001.studioe5.edudeploy.com/ HTTP/2 302 location: https://test-wp-001.studioe5.edudeploy.com/wp-admin/install.php ... HTTP/2 200 ``` - Certificat Let’s Encrypt obtenu automatiquement par Caddy (`tls { on_demand }`). - Le resolver réécrit les en-têtes `Location` et le contenu HTML pour passer de `http://` à `https://`. ## 📁 Fichiers modifiés (non exhaustif) - `agent/tailscale.go` – lancement `tailscaled` + `tailscale up`, gestion start/stop/status. - `agent/websocket.go` – handlers `start_vpn` / `stop_vpn`, `ensureTailscale()`. - `agent/docker.go` – remplacement des placeholders `{PORT}` et `{INSTANCE_ID}` dans les compose. - `docker-compose.yml` – ajout du sidecar `resolver-vpn`, suppression des `cap_add`/`ip route` obsolètes sur `server`/`resolver`. - `Caddyfile` – configuration on-demand TLS pour les instances. - `.env` – clé pré-auth Headscale mise à jour (clé réutilisable). ## 🧪 Tests / environnement de test actuel Agent de test lancé en arrière-plan : - data-dir : `/tmp/studioe5-test-clienta` - node-id : `vps-8fc665eb` - tailnet IP actuelle : `100.64.0.8` - PID : `3151830` (lancé le 2026-06-23 09:36 UTC) Instance de test créée : - ID : `test-wp-001` - Node : `vps-8fc665eb` - Port : `8001` - Template : `wordpress-wordpress-latest` - État : WordPress répond sur `http://127.0.0.1:8001` **et en HTTPS public sur `https://test-wp-001.studioe5.edudeploy.com/`**. ## 🛠️ Commandes utiles pour reprendre ### Voir l’agent de test ```bash pgrep -a studioe5-agent ``` ### Relancer l’agent de test (si besoin) ```bash mkdir -p /tmp/studioe5-test-clienta cat > /tmp/studioe5-test-clienta/studioE5-config.json < HTTP/2 302 -> HTTP/2 200 (WordPress install.php) ``` Le flux `UI → API → WebSocket → agent → Docker → VPN → Caddy → HTTPS public` est fonctionnel. ## 💻 Téléchargement de l’agent L’agent est servi par Caddy depuis le dossier `agent/` monté dans le conteneur Caddy (`./agent:/usr/share/caddy/agent`). ### Binaires disponibles - **Windows (archive complète)** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.0-windows.zip` - Contient `studioE5-agent.exe` + `tailscale-bin/windows/` (`tailscale.exe`, `tailscaled.exe`, `wintun.dll`) + `README-Windows.txt`. - **Windows (exécutable seul)** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.0.exe` - Nécessite d’avoir installé Tailscale Windows séparément ou d’avoir les binaires dans `tailscale-bin/windows/`. - **Linux** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.0` ### Builder / préparer les binaires ```bash cd /opt/studioe5-client-a/agent # 1. Télécharger les binaires Tailscale Windows (nécessite msitools) ./download-tailscale-bins.sh 1.98.4 # 2. Builder l’agent pour Windows et Linux (macOS nécessite CGO) ./build.sh ``` Le `build.sh` génère automatiquement `studioE5-agent-v0.3.0-windows.zip` et copie les binaires versionnés dans `server/public/`. ### Flow d’activation zéro-config (modèle commercialisable) L’élève/employé n’a **aucune configuration technique** à saisir : 1. **Télécharger** l’agent Windows (`studioE5-agent-v0.3.0-windows.zip`). 2. **Extraire** et **lancer** `studioE5-agent.exe`. 3. **Entrer le code d’activation** à 6 caractères fourni par l’établissement (affiché dans l’UI locale `http://localhost:7070`). 4. L’agent contacte le serveur, le serveur vérifie le code et renvoie **automatiquement** : - l’identité de l’élève (`studentName`) - l’URL Headscale - la clé pré-auth Headscale 5. L’agent sauvegarde ces informations localement et **démarre automatiquement le VPN**. 6. L’agent est alors visible dans le dashboard et peut recevoir des instances. ### Configuration manuelle (mode debug / admin) Si besoin, on peut toujours forcer une config via `data/studioE5-config.json` : ```json { "server": "wss://studioe5.edudeploy.com/api/websocket", "headscale_url": "https://headscale.studioe5.edudeploy.com", "headscale_auth_key": "CLE_PREAUTH_ICI", "node_id": "IDENTIFIANT_DU_POSTE", "data_dir": "C:\\studioE5-agent\\data" } ``` > ⚠️ `headscale_auth_key` doit être une clé pré-auth réutilisable valide pour le tailnet studioe5. Ne jamais commiter cette clé. Lancement : ```powershell .\studioE5-agent.exe -no-tray -data-dir C:\studioE5-agent\data ``` ## 📋 Prochaines étapes à faire - [x] ~~Attendre la fin du rate limit Let’s Encrypt~~ (levé le 2026-06-23). - [x] ~~Relancer un test HTTPS sur `https://test-wp-001.studioe5.edudeploy.com/`~~ → **OK** (HTTP/2 200). - [x] ~~Créer une branche dédiée et commiter les modifications VPN on-demand~~ → branche `feat/studioe5-vpn-ondemand`, commit `124543d`. Push vers Gitea à faire dès que le remote sera accessible (actuellement `localhost:3001` et `gitea.alfrednobel.edudeploy.com` injoignables). - [x] ~~Tester le flux complet depuis l’interface web~~ → **OK** via l’API authentifiée (`POST /api/instances`), instance `cmqqgrur20001lw67t2bdgzkg` accessible en HTTPS public. - [ ] **Obtenir un certificat wildcard** pour `*.studioe5.edudeploy.com` (voir étude ci-dessous). - [ ] **Nettoyer les instances/agent de test** une fois le wildcard en place et le push effectué. - [x] ~~Packager les binaires Tailscale pour Windows~~ → **OK**, `download-tailscale-bins.sh` + `studioE5-agent-v0.3.0-windows.zip` prêt. - [ ] **Nettoyer les anciens nodes/volumes Headscale** créés pendant les tests. - [ ] **Documenter la procédure de mise en production** pour le client A (config agent, clés Headscale, ports, etc.). ## 💡 Améliorations UI envisagées ### Console / log intégré dans l’agent Plutôt que de laisser Windows ouvrir une fenêtre noire à chaque commande `podman`/`docker`/`tailscale`, rediriger le `Stdout`/`Stderr` de chaque commande vers l’UI locale de l’agent (`http://localhost:7070`). Bénéfices : - Expérience utilisateur plus propre et commercialisable. - Diagnostic facilité : l’utilisateur voit exactement ce qui se passe (téléchargement d’image, démarrage, installation PrestaShop, etc.). Implémentation : 1. Remplacer `cmd.Stdout = os.Stdout` par un `io.Pipe()` ou `bytes.Buffer` dans `docker.go`, `tailscale.go`, etc. 2. Envoyer les lignes de log au frontend via le WebSocket existant (`agent/ui/websocket`). 3. Afficher les logs dans un panneau dédié du HTML. ### Barre de progression Associer des étapes connues à une barre de progression dans l’UI : | Étape | Poids | |-------|-------| | Connexion au serveur | 10 % | | Démarrage du VPN | 25 % | | Téléchargement de l’image Docker | 50 % | | Création de la base de données | 70 % | | Installation de PrestaShop/WordPress | 90 % | | Instance prête | 100 % | L’agent envoie des messages `progress` au frontend à chaque étape franchie. ## 🔒 Étude certificat wildcard `*.studioe5.edudeploy.com` ### Pourquoi passer en wildcard ? Avec `tls { on_demand }`, Caddy émet **un certificat Let’s Encrypt par sous-domaine d’instance**. Cela expose au rate limit de 50 certificats par domaine principal (`edudeploy.com`) sur 7 jours. Un certificat wildcard unique (`*.studioe5.edudeploy.com`) couvre tous les sous-domaines d’instances et évite ce problème. ### Contrainte technique Un certificat wildcard nécessite le **challenge DNS-01** (le challenge HTTP-01 ne permet pas de valider `*.domain.tld`). Caddy doit donc pouvoir créer un enregistrement TXT automatiquement chez le registrar DNS. ### Infomaniak (registrar actuel) Le DNS de `edudeploy.com` est chez **Infomaniak** : ```bash dig NS edudeploy.com +short # nsany1.infomaniak.com. # nsany2.infomaniak.com. ``` Il existe un module Caddy DNS pour Infomaniak : - Repository : `github.com/caddy-dns/infomaniak` - Nécessite un **token API Infomaniak** avec droits DNS. ### Implémentation à envisager 1. **Générer un token API Infomaniak** (compte client A ou compte dédié avec accès au domaine). 2. **Builder une image Caddy custom** avec le module : ```dockerfile FROM caddy:2-builder AS builder RUN xcaddy build --with github.com/caddy-dns/infomaniak FROM caddy:2-alpine COPY --from=builder /usr/bin/caddy /usr/bin/caddy ``` 3. **Modifier le `Caddyfile`** pour gérer le wildcard : ```caddy *.studioe5.edudeploy.com { tls { dns infomaniak {env.INFOMANIAK_API_TOKEN} } reverse_proxy resolver:2020 { header_up Host {host} } } ``` 4. **Ajouter le token dans `.env`** et le passer au conteneur Caddy. 5. Supprimer ou ajuster le bloc `:443` actuel qui utilise `on_demand` pour les instances. ### Alternative sans module DNS Obtenir le certificat wildcard manuellement (Certbot DNS-01, acheté, etc.) et le charger dans Caddy : ```caddy *.studioe5.edudeploy.com { tls /data/certs/wildcard.crt /data/certs/wildcard.key reverse_proxy resolver:2020 { header_up Host {host} } } ``` Inconvénient : renouvellement manuel. ## 🔧 Notes techniques - Le conteneur `resolver-vpn` utilise `network_mode: service:resolver` pour partager le netns avec le resolver. - L’agent utilise `tailscaled --tun=userspace-networking` ; le resolver-vpn utilise un vrai TUN (`tailscale0`). - Le `Caddyfile` actuel utilise `tls { on_demand }` pour les instances. En cas de nouvelle rate limit, on peut temporairement remettre `tls internal` dans le bloc `:443` pour valider le flux sans certificat public.