Files
veye-lalwa/systemd/veille-web.service
T
Cyber MawonajandClaude Opus 5 bdeaa9fa7f 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>
2026-07-25 22:51:05 -04:00

83 lines
3.2 KiB
Desktop File

# Application web de la veille législative (SvelteKit, adapter-node).
#
# Démarrée par veille-web.socket à la première requête, elle s'arrête d'elle-même
# après IDLE_TIMEOUT secondes sans trafic, et systemd la réveille à la suivante.
#
# Node ≥ 20.6 requis : les variables ne sont PAS chargées automatiquement en
# production, d'où --env-file.
[Unit]
Description=Veille législative — application web
Documentation=file:///opt/veille-legislative/README.md
Requires=veille-web.socket
After=network.target veille-web.socket
[Service]
Type=simple
User=veille
Group=veille
WorkingDirectory=/opt/veille-legislative/web
# `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
# ── 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
# Durcissement : l'application ne fait que lire la base.
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/opt/veille-legislative/data
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
LockPersonality=true
StandardOutput=journal
StandardError=journal
SyslogIdentifier=veille-web
[Install]
WantedBy=multi-user.target