Rapatrie dans dev les mises à jour de dépendances mergées sur main : #142 (SonarQube ignoré pour Dependabot), #129 checkout v7, #130 setup-uv v7, #132 setup-node v7, #128 upload-artifact v7, #131 download-artifact v8, #127 Node 26 (image et CI frontend), #126 nginx 1.31-alpine, #133 pandas 3.0.6 et ruff 0.16.8, #134 Angular 22.1.7, jsdom 30, prettier 3.9.8 (TypeScript 6 et vitest 4 conservés, majeures ignorées côté Dependabot). Conflit README.md : statuts « En place » de main, « Quatre DAGs » de dev (#138).
Reverse proxy
Terminaison TLS et routage de la stack déployée. Seul composant publié sur le réseau : il écoute en 80 et 443, et rien d'autre ne sort du réseau Compose.
nginx.conf: blochttp, journalisation, compression, zones de limitation de débit.conf.d/enervision.conf: redirection 80 vers 443, terminaison TLS, en-têtes de sécurité, routage.tls/: les deux fichiers que nginx lit,fullchain.pemetprivkey.pem. Ignorés par git.acme-deploy-hook.sh: recopie le résultat de certbot danstls/.
Pas de Dockerfile : l'image officielle nginx:1.31-alpine est utilisée telle quelle et la
configuration est montée en volume par docker-compose.prod.yml.
L'overlay emploie les marqueurs !override et !reset, qui demandent Docker Compose 2.24.4
ou plus récent. Sur une version antérieure, la fusion échoue au lieu de dépublier les ports.
Les ports publiés sont PROXY_HTTP_PORT et PROXY_HTTPS_PORT, 80 et 443 par défaut. Quand deux
environnements partagent la machine (ADR 0009),
la recette publie 8443 et ramène son port 80 sur 127.0.0.1:8081 : la redirection ci-dessous
renvoie vers https://$host sans port, donc vers la production. PUBLIC_ORIGIN porte alors
l'origine avec son port pour le CORS et le lien de réinitialisation.
Routage
| Chemin | Destination | Remarque |
|---|---|---|
/.well-known/acme-challenge/ |
/var/www/certbot sur le port 80 |
Seul chemin non redirigé vers HTTPS |
/api/v1/auth/ + login, password, forgot-password, reset-password |
backend:8000 |
Zone resserrée, 30 requêtes par minute |
/api/ |
backend:8000 |
Préfixe /api/v1 préservé tel quel, 20 requêtes par seconde |
/ |
frontend:3000 |
Le SPA, qui renvoie index.html sur les routes inconnues |
La zone resserrée ne couvre que les routes qui vérifient un secret. /auth/me et /auth/refresh
partent à chaque chargement de page et restent dans la zone générale : derrière un NAT, où une
seule adresse porte tous les postes, les y soumettre aurait produit des 429 en usage normal.
L'interface Airflow, celle de Mailpit et la base ne passent pas par le proxy : l'overlay les
ramène sur 127.0.0.1, donc joignables par tunnel SSH et pas autrement. Les publier derrière le
proxy demanderait une authentification propre, qui n'est pas la leur.
/docs, /redoc, /openapi.json, /static et /metrics sont montés par l'API à la racine,
pas sous /api. Ils tombent donc dans location /, donc sur le SPA : ils ne sont pas joignables
depuis l'extérieur, sans qu'aucune règle de blocage ait à être écrite. Y toucher, c'est les
exposer.
Certificat : deux modes, un seul emplacement
nginx lit toujours tls/fullchain.pem et tls/privkey.pem. Seule leur fabrication change, la
configuration n'a jamais à bouger.
Démonstration, certificat auto-signé
make tls-selfsigned PUBLIC_HOST=enervision.local
make stack-up
Le navigateur avertira d'un émetteur inconnu : c'est attendu, et c'est le seul mode exploitable tant que la machine cible n'a pas de nom de domaine public.
Let's Encrypt
Le défi HTTP-01 exige un nom de domaine résolvable publiquement et le port 80 joignable
depuis Internet. La cible documentée aujourd'hui (ssh_host = "10.0.0.10", serveur de l'école)
ne remplit ni l'une ni l'autre condition : le chemin ci-dessous est livré et documenté, il n'a
pas été exercé.
make stack-up # nginx doit tourner pour servir le défi
make tls-acme PUBLIC_HOST=enervision.fr ACME_EMAIL=ops@enervision.fr
Renouvellement, à passer en tâche planifiée sur la machine :
17 3 * * * cd /srv/enervision && make tls-renew >> /var/log/enervision-tls.log 2>&1
Pour un domaine sans port 80 entrant, le défi DNS-01 est l'alternative : elle demande un greffon certbot propre au fournisseur DNS et un jeton d'API, hors périmètre à ce jour.
Vérifier la configuration sans démarrer la stack
nginx -t charge les certificats : tls/ doit être rempli, par make tls-selfsigned au besoin.
docker run --rm \
-v "$PWD/infra/proxy/nginx.conf:/etc/nginx/nginx.conf:ro" \
-v "$PWD/infra/proxy/conf.d:/etc/nginx/conf.d:ro" \
-v "$PWD/infra/proxy/tls:/etc/nginx/tls:ro" \
nginx:1.31-alpine nginx -t
Monter infra/proxy/ entier sur /etc/nginx échouerait : mime.types vient de l'image.