Déploiement : plus aucune valeur d'exemple à corriger à la main
L'unité web portait ORIGIN=https://veille.example.org : un fichier versionné qu'il fallait éditer à chaque déploiement, et dont l'oubli casse silencieusement les soumissions de formulaire. Remplacé par PROTOCOL_HEADER / HOST_HEADER : l'application déduit son origine des en-têtes du reverse proxy et fonctionne donc sur n'importe quel domaine, sans édition. Vérifié en exécutant réellement le binaire construit : deux domaines différents servis par le même processus, HTTP 200 dans les deux cas, et un ORIGIN figé l'emporte bien sur les en-têtes. Au passage, une affirmation fausse que j'avais écrite en commentaire : « le .env l'emporte sur les variables systemd ». C'est l'inverse — le --env-file de Node ne remplace pas une variable déjà présente dans l'environnement (constaté sur Node 24). Le commentaire dit désormais pourquoi ORIGIN dans .env fonctionne quand même : parce que l'unité ne le déclare pas. Et un contrôle mécanique interdit désormais de le redéclarer. ExecStart passe par /usr/bin/env : NodeSource installe node dans /usr/bin, une compilation manuelle dans /usr/local/bin, un chemin figé échouait sur l'un des deux. Deux contrôles ajoutés à make verifier : aucune valeur d'exemple active dans les unités systemd, et ORIGIN laissé au .env. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
29424afdd5
commit
bdeaa9fa7f
+10
-5
@@ -51,10 +51,15 @@ VEILLE_NOTIF_DESTINATAIRE=
|
||||
# Node ≥ 20.6 : lancer avec `node --env-file=.env build`
|
||||
HOST=127.0.0.1
|
||||
PORT=3971
|
||||
# Obligatoire derrière un reverse proxy, sinon « Cross-site POST form
|
||||
# submissions are forbidden ». Alternative : PROTOCOL_HEADER + HOST_HEADER.
|
||||
ORIGIN=https://veille.example.org
|
||||
# PROTOCOL_HEADER=x-forwarded-proto
|
||||
# HOST_HEADER=x-forwarded-host
|
||||
# Mise en sommeil de l'app sans trafic (activation par socket systemd).
|
||||
IDLE_TIMEOUT=300
|
||||
|
||||
# Origine des requêtes. Rien à renseigner dans le cas courant : l'unité
|
||||
# systemd fait déduire l'origine des en-têtes posés par le reverse proxy
|
||||
# (PROTOCOL_HEADER / HOST_HEADER), ce qui fonctionne quel que soit le domaine.
|
||||
#
|
||||
# Décommentez seulement si vous préférez la figer — adapter-node la retient
|
||||
# alors d'office. Cela fonctionne parce que l'unité systemd ne déclare PAS
|
||||
# ORIGIN : le `--env-file` de Node ne remplace jamais une variable déjà
|
||||
# présente dans l'environnement.
|
||||
# ORIGIN=https://votre-domaine
|
||||
|
||||
@@ -146,12 +146,26 @@ démarre Node qu'à la première requête ; sans trafic pendant `IDLE_TIMEOUT`
|
||||
(300 s), elle s'arrête. Sur un site de veille peu fréquenté, l'empreinte mémoire
|
||||
tombe à zéro entre deux visites — ce qui compte sur un serveur à 5 € par mois.
|
||||
|
||||
Avant de démarrer, ajustez `ORIGIN` dans `veille-web.service` : sans lui, les
|
||||
soumissions de formulaire sont refusées derrière un reverse proxy.
|
||||
**Aucun fichier n'est à éditer avant de démarrer.** L'unité déduit son origine
|
||||
des en-têtes posés par le reverse proxy (`PROTOCOL_HEADER` / `HOST_HEADER`),
|
||||
donc elle fonctionne quel que soit votre domaine. Sans cette origine,
|
||||
adapter-node refuserait les soumissions de formulaire (« Cross-site POST form
|
||||
submissions are forbidden »).
|
||||
|
||||
Ces en-têtes ne sont dignes de confiance que parce que l'application n'écoute
|
||||
que sur `127.0.0.1` : seul le proxy local peut les poser. **N'exposez jamais le
|
||||
port 3971 directement** — l'origine deviendrait falsifiable par le client.
|
||||
|
||||
Pour figer l'origine plutôt que la déduire, renseignez `ORIGIN=` dans `.env` :
|
||||
adapter-node la retient d'office, sa résolution s'écrivant
|
||||
`origin || get_origin(headers)`.
|
||||
|
||||
### Reverse proxy
|
||||
|
||||
**Caddy** (le plus court, HTTPS automatique) :
|
||||
Remplacez `veille.example.org` par votre domaine dans les deux exemples.
|
||||
|
||||
**Caddy** (le plus court, HTTPS automatique — il pose les en-têtes attendus
|
||||
sans configuration supplémentaire) :
|
||||
|
||||
```caddy
|
||||
veille.example.org {
|
||||
@@ -180,8 +194,9 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
Avec nginx, remplacez `ORIGIN` par `PROTOCOL_HEADER=x-forwarded-proto` et
|
||||
`HOST_HEADER=x-forwarded-host` dans le service.
|
||||
Les trois en-têtes `X-Forwarded-*` de cet exemple ne sont pas décoratifs :
|
||||
ce sont eux dont l'application déduit son origine. Les omettre casserait les
|
||||
soumissions de formulaire.
|
||||
|
||||
### Vérifier
|
||||
|
||||
|
||||
@@ -67,6 +67,24 @@ nb_polices=$(find web/static/polices -name '*.woff2' 2>/dev/null | wc -l)
|
||||
ok "polices auto-hébergées ($nb_polices fichiers woff2)" ||
|
||||
ko "polices non auto-hébergées — lancer npm run polices"
|
||||
|
||||
titre "Déploiement — pas de valeur d'exemple à corriger à la main"
|
||||
|
||||
# Les unités systemd sont copiées telles quelles dans /etc/systemd/system :
|
||||
# un domaine d'exemple qui y traîne casse le déploiement sans le dire.
|
||||
gabarits=$(grep -nE '^[^#]*(example\.(org|com)|votre-domaine|CHANGEME|TODO)' systemd/*.service systemd/*.socket systemd/*.timer 2>/dev/null || true)
|
||||
if [ -z "$gabarits" ]; then
|
||||
ok "aucune valeur d'exemple active dans les unités systemd"
|
||||
else
|
||||
ko "valeur d'exemple à remplacer dans une unité systemd :"
|
||||
echo "$gabarits"
|
||||
fi
|
||||
|
||||
if grep -qE '^[^#]*Environment=ORIGIN=' systemd/veille-web.service; then
|
||||
ko "ORIGIN déclaré dans l'unité : le .env ne pourrait plus le surcharger"
|
||||
else
|
||||
ok "ORIGIN laissé au .env, l'origine est déduite des en-têtes du proxy"
|
||||
fi
|
||||
|
||||
titre "§8 — livrables"
|
||||
|
||||
for chemin in pipeline web data systemd tests README.md README-pipeline.md .env.example Makefile; do
|
||||
|
||||
@@ -17,16 +17,46 @@ Type=simple
|
||||
User=veille
|
||||
Group=veille
|
||||
WorkingDirectory=/opt/veille-legislative/web
|
||||
ExecStart=/usr/bin/node --env-file=/opt/veille-legislative/.env build
|
||||
# `env` plutôt qu'un chemin figé : NodeSource installe dans /usr/bin, une
|
||||
# compilation manuelle dans /usr/local/bin, et les deux sont dans le PATH par
|
||||
# défaut de systemd. Un chemin en dur échouerait sur la moitié des machines.
|
||||
ExecStart=/usr/bin/env node --env-file=/opt/veille-legislative/.env build
|
||||
|
||||
Environment=NODE_ENV=production
|
||||
Environment=VEILLE_DB=/opt/veille-legislative/data/veille.db
|
||||
# Mise en sommeil après cinq minutes sans requête.
|
||||
Environment=IDLE_TIMEOUT=300
|
||||
# Obligatoire derrière un reverse proxy, sinon les soumissions de formulaire
|
||||
# sont refusées (« Cross-site POST form submissions are forbidden »).
|
||||
# Alternative : PROTOCOL_HEADER=x-forwarded-proto + HOST_HEADER=x-forwarded-host
|
||||
Environment=ORIGIN=https://veille.example.org
|
||||
|
||||
# ── Origine des requêtes, derrière un reverse proxy ──────────────────────────
|
||||
#
|
||||
# Sans indication d'origine, adapter-node refuse les soumissions de formulaire
|
||||
# (« Cross-site POST form submissions are forbidden »).
|
||||
#
|
||||
# Deux façons de la lui donner. On retient ici celle qui ne dépend pas du
|
||||
# domaine : l'application déduit l'origine des en-têtes que pose le reverse
|
||||
# proxy. Cette unité fonctionne donc telle quelle, quel que soit le domaine —
|
||||
# aucun fichier versionné n'est à éditer au déploiement.
|
||||
#
|
||||
# Ces en-têtes ne sont dignes de confiance que parce que l'application n'écoute
|
||||
# que sur 127.0.0.1 (voir veille-web.socket) : seul le proxy local peut les
|
||||
# poser. Exposer directement le port rendrait l'origine falsifiable par le
|
||||
# client — ne le faites pas.
|
||||
#
|
||||
# Le reverse proxy DOIT poser ces trois en-têtes ; les exemples nginx et Caddy
|
||||
# du README le font.
|
||||
Environment=PROTOCOL_HEADER=x-forwarded-proto
|
||||
Environment=HOST_HEADER=x-forwarded-host
|
||||
Environment=ADDRESS_HEADER=x-forwarded-for
|
||||
Environment=XFF_DEPTH=1
|
||||
|
||||
# Alternative : figer l'origine au lieu de la déduire. Renseignez
|
||||
# ORIGIN=https://votre-domaine dans /opt/veille-legislative/.env ; adapter-node
|
||||
# la retient d'office, sa résolution s'écrivant `origin || get_origin(headers)`.
|
||||
#
|
||||
# Cela ne fonctionne QUE parce que ORIGIN n'est pas déclarée ci-dessus : le
|
||||
# `--env-file` de Node ne remplace pas une variable déjà présente dans
|
||||
# l'environnement, c'est l'environnement qui gagne (vérifié sur Node 24). Ne
|
||||
# déclarez donc jamais ORIGIN ici, sinon le fichier .env resterait sans effet.
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
Reference in New Issue
Block a user