Files

6.3 KiB

Déploiement

Ustagammon est un site statique (PWA, ADR 0009) : des fichiers HTML, JavaScript, le moteur en WebAssembly et ses données. L'application est à la racine ; les pages de test du moteur de l'étape 0b ont été retirées (ADR 0009, amendement du 2026-11-03). Il est publié sur CapRover, machine sans-pub (https://captain.cloud.sans.pub), app ustagammon, sur https://ustagammon.sans.pub.

Le site est construit et testé sur le PC, pas sur le serveur. La construction est lourde (Emscripten, génération des données du moteur) et déjà outillée en local. make deploy-prod envoie à CapRover une archive qui contient le site prêt, un Dockerfile et un Caddyfile (deploy/). Le serveur ne fait que copier les fichiers dans une image Caddy (caddy:2.8.4-alpine), qui les sert en HTTP derrière le HTTPS de CapRover.

Prérequis

  • La chaîne d'outils du projet : make setup.
  • CLI CapRover, installée avec Node par fnm (le script la trouve seul) :
    eval "$(fnm env)"; fnm use lts-latest
    
  • Session CapRover valide. Le jeton expire ; pour vérifier :
    caprover api -n sans-pub -t /user/system/info -m GET -d '{}' -o false
    
    En cas de not valid anymore : caprover login dans un vrai terminal.
  • L'app ustagammon existe dans CapRover (créée le 2026-11-02) : sans volume (rien n'est stocké côté serveur), port du conteneur 80, domaine ustagammon.sans.pub avec HTTPS forcé.

Publier

Depuis main, à jour avec origin/main (après fusion de la MR) :

make deploy-prod

Le script refuse de publier si l'arbre n'est pas propre, si l'on n'est pas sur main, si main diffère d'origin/main, ou si la session CapRover a expiré. Il lance make lint et make test, assemble le site (make package), puis caprover deploy -t build/ustagammon.tar.

Pour une autre machine ou une autre app : CAPROVER_MACHINE=… CAPROVER_APP=… make deploy-prod.

Ce qui est publié

  • make site assemble build/site/ (9 Mo) :
    • le contenu de web/ à la racine : la page de l'application (index.html, app.css), le manifeste (manifest.webmanifest), les icônes (icons/), le service worker (sw.js), le Web Worker du moteur (engine-worker.mjs, engine-wasm.mjs) et les pages de test sous moteur/ ;
    • l'application TypeScript compilée (build/web/src/) sous app/ ;
    • le moteur (engine.mjs, engine.wasm, engine.data, positions.json) sous wasm/ ;
    • des copies de docs/glossaire/ et docs/scenarios/ sous docs/, lues par l'aide de l'application (ADR 0008) ;
    • version.json avec le commit publié ;
    • enfin, scripts/service-worker.sh écrit en tête de sw.js la liste de tous ces fichiers et une empreinte de leur contenu.
  • make package ajoute deploy/ et produit build/ustagammon.tar (environ 9 Mo, 7,3 Mo transférés grâce à la compression).
  • tests/test_site.sh (dans make test) construit l'image de production en local, la lance et vérifie ce que reçoit un navigateur : application, pages de test, aide, manifeste et icônes, liste du service worker, types MIME (application/wasm pour le moteur), compression gzip des données, en-têtes dont la politique de sécurité, et commit de version.json.
  • make test-browser (hors de make test, plusieurs minutes) joue une partie complète par l'interface dans Chromium et Firefox sans écran, sur la même image, puis vérifie la reprise, l'aide, le hors ligne (Chromium seulement : Firefox sous Playwright refuse toute navigation « hors ligne », on y vérifie que le cache est complet et que la page rechargée est servie par le service worker) et la politique de sécurité. Captures d'écran dans build/browser-shots/.

Hors ligne et mises à jour. Le service worker met tous les fichiers du site en cache à la première visite (environ 9 Mo), puis sert tout depuis ce cache, avec ou sans réseau. À chaque publication, l'empreinte écrite dans sw.js change dès qu'un fichier a changé : le navigateur, qui revérifie sw.js à chaque ouverture, installe la nouvelle version (tout le site est retéléchargé), qui prend la main et efface l'ancien cache. La page déjà ouverte continue sur l'ancienne version ; le lancement suivant utilise la nouvelle. Une publication sans changement de fichier garde le même sw.js : rien n'est retéléchargé. Le service worker exige https (ou localhost) : avec make deploy, en http sur le réseau local, l'application fonctionne, mais pas hors ligne.

Réglages du serveur (deploy/Caddyfile) : compression zstd ou gzip, y compris pour les données du moteur ; Cache-Control: no-cache (les noms de fichiers ne changent pas d'une version à l'autre, le navigateur revalide chaque fichier) ; X-Content-Type-Options: nosniff ; Referrer-Policy: no-referrer ; et une politique de sécurité du contenu (Content-Security-Policy) : tout vient du site lui-même, aucun script ni style en ligne, aucun eval, seule la compilation du WebAssembly est permise ('wasm-unsafe-eval'). Elle est vérifiée par tests/test_site.sh (en-tête présent) et par make test-browser : aucune violation signalée par Chromium ni Firefox pendant toute une partie (moteur, Web Worker, service worker, aide), et un script en ligne ajouté exprès à la page est bien bloqué.

Vérifier

curl -s https://ustagammon.sans.pub/version.json      # commit publié
curl -sI https://ustagammon.sans.pub/wasm/engine.wasm  # application/wasm
curl -sI https://ustagammon.sans.pub/ | grep -i content-security  # CSP
curl -s https://ustagammon.sans.pub/sw.js | head -2             # version du cache
ssh sans.pub 'sudo docker service ps srv-captain--ustagammon --format "{{.Image}} {{.CurrentState}}" | head -2'

Puis ouvrir le site sur le téléphone : le plateau s'affiche et une consigne remplace « Chargement du moteur… ».

Retour arrière

Dans CapRover, onglet Deployment de l'app ustagammon : redéployer une image précédente (img-captain-ustagammon:N). Rien n'est stocké côté serveur : aucun risque pour des données.

Incidents connus

Voir la-main-libre (docs/technique/deploiement.md) pour le registre Docker de CapRover dont le certificat expire : le build réussit, l'envoi échoue, la production n'est pas touchée ; redémarrer captain-registry puis relancer.