Une plateforme qu'une structure doit pouvoir héberger seule
Notre projet consistait au départ à concevoir une plateforme d'aide à l'apprentissage de l'informatique, destinée d'abord aux étudiants et aux lycéens. Après plusieurs jours de réflexion, nous l'avons réorienté vers une plateforme e-learning libre que n'importe quelle structure, école, entreprise ou association, pourrait reprendre, adapter et héberger elle-même pour garder la maîtrise de ses données. Nous avons aussi décidé d'héberger nous-mêmes l'instance principale de cette plateforme pour y proposer nos propres cours d'informatique et démontrer ainsi la viabilité de l'ensemble.
Ce revirement a été un enjeu considérable pour le volet infrastructure. La question n'était plus seulement de savoir si l'application fonctionnait, mais si un tiers pouvait la déployer, la mettre à jour et la surveiller sans nous, puisqu'une solution présentée comme libre et souveraine doit pouvoir vivre sur le serveur de son utilisateur sans dépendre d'une équipe qui connaît les astuces pour la faire tourner. Mon rôle a donc consisté à construire autour du code applicatif la chaîne qui permet de le tester automatiquement, de le déployer de façon reproductible, de le sécuriser et de l'observer en production, en la gardant modulaire et portable.
Trois services sous Docker Compose supervisés en surcouche
L'application tient en trois services orchestrés par Docker Compose : une base PostgreSQL, un backend Java Spring Boot et un frontend Next.js, chacun construit en plusieurs étapes pour ne garder qu'une image légère, le backend attendant que la base soit prête avant de démarrer. En production, Caddy se place devant eux en reverse proxy, obtient et renouvelle seul les certificats Let's Encrypt, ajoute les en-têtes de sécurité comme HSTS ou la protection contre le clickjacking, et écrit des logs d'accès en JSON exploitables par la supervision.
Le serveur est un VPS que j'ai loué et configuré, avec un nom de domaine acheté et une zone DNS qui pointe vers lui, condition indispensable pour que l'autorité de certification puisse délivrer le certificat. Un script d'installation rend une machine vierge opérationnelle en une seule commande : il installe Docker, durcit l'hôte en n'ouvrant que les ports SSH et web et en installant fail2ban, puis génère des secrets aléatoires. Ce script peut être rejoué sans rien écraser et ne réécrit jamais un fichier de configuration existant.
La supervision s'ajoute en surcouche de six conteneurs. Prometheus collecte les métriques du système, des conteneurs et de la JVM, Loki et Promtail centralisent les logs, et Grafana les présente dans des dashboards provisionnés par fichiers, avec quinze jours de rétention pour les métriques et sept pour les logs.
De Dokploy à un monorepo piloté via scripts
Nous avons commencé avec Dokploy, sur une organisation en deux dépôts séparés pour le backend et le frontend. Cet outil nous a permis de mettre rapidement en place un déploiement continu minimal et propre, et d'obtenir des métriques sans effort. À mesure que le projet avançait, nous avons voulu davantage de liberté sur le déploiement et une chaîne capable de passer à l'échelle sans entraver ceux qui reprendraient la plateforme, car imposer Dokploy à un tiers revenait à lui imposer un outil de plus. Nous sommes donc passés à un monorepo dont le déploiement repose sur deux scripts que j'ai écrits, l'installation et la mise à jour, que n'importe qui peut lire et exécuter sur son propre serveur.
Le script de mise à jour sauvegarde la base, récupère le nouveau code, reconstruit les services puis attend que leur health check réponde. Si le service ne repart pas, il effectue un rollback automatique du code et restaure la base sauvegardée. Ce rollback rend le script plus long à écrire, mais il permet à une structure sans équipe d'exploitation de mettre à jour la plateforme sans risquer de la laisser hors service. Un verrou empêche deux mises à jour simultanées et les sauvegardes tournent pour ne pas saturer le disque. Un workflow GitHub Actions est prêt à déclencher cette mise à jour par SSH dès qu'un hôte est configuré dans les secrets du dépôt, et il s'ignore sinon, ce qui évite d'échouer sur un fork.
La supervision est auto-hébergée, par cohérence avec la promesse du projet, pour un coût nul et pour ce que sa mise en place m'apprenait. Aucun des six conteneurs n'expose de port public, et Grafana n'est accessible que par un tunnel SSH : son historique compte plusieurs failles connues, ce qui m'a conduit à ne pas l'exposer, même derrière une authentification. Dans la même logique, les endpoints de health check du backend sont ouverts par une liste explicite dans Spring Security au lieu d'une exposition large.
Pour l'intégration continue, j'ai séparé ce qui doit être rapide de ce qui peut attendre. Le pipeline des pull requests ne teste que les parties modifiées, vérifie la cohérence des migrations de base et la parité des clés de traduction entre le français et l'anglais, cherche des secrets oubliés dans le code et contrôle les dépendances, et un job de synthèse unique sert de contrôle obligatoire à la protection de la branche principale. Les analyses lourdes, comme CodeQL, Trivy sur les dépendances et les images ou le score OpenSSF Scorecard, passent dans un workflow nocturne séparé qui produit aussi un SBOM accompagné d'une attestation de provenance signée. J'ai enfin dupliqué la CI pour GitLab afin que le projet ne soit pas enfermé dans une seule forge.

Un incident de production diagnostiqué le soir même
Comme le VPS était partagé avec un autre projet, Grafana entrait en conflit de port avec un service déjà en place, ce que j'ai résolu en le déplaçant. Plus tard, le backend s'est mis à redémarrer en boucle après une reconstruction, et les logs ont permis d'en trouver la cause le soir même : une migration de base de données modifiée après son application, dont le checksum ne correspondait plus à celui enregistré. Après avoir vérifié que le schéma était intact, j'ai réaligné le checksum et relancé le service, puis proposé à l'équipe de ne plus modifier une migration appliquée et de n'ajouter que des migrations nouvelles.
Installable en une commande et en migration vers un serveur dédié
La plateforme permet aux professeurs de créer et publier des cours et de gérer des groupes, aux utilisateurs de consulter ces cours, et aux administrateurs d'adapter le branding à l'image de leur structure. Elle est surtout réellement auto-hébergeable : installable en une commande, mise à jour de façon sûre et réversible, servie en HTTPS et supervisée, avec une CI qui sert de point de contrôle unique avant toute fusion et une chaîne dont la sécurité est outillée et non simplement déclarée.
L'instance principale est en cours de migration vers un nouveau serveur de production. Le premier VPS hébergeait plusieurs projets, dont un derrière Dokploy, et ce changement permet de configurer le Caddyfile proprement sur une machine dédiée à Codestar. Les prochaines évolutions portent sur les fonctionnalités pédagogiques et sur l'expérience utilisateur.