Déploiement

Fournir le token de registre avant le build, configurer l'environnement de production et le reverse proxy.

Un projet LRVO se déploie comme n'importe quelle application Next.js, avec deux particularités : l'accès au registre privé au moment du build, et quelques variables qui changent de comportement en production.

1. Le token du registre, avant le build

npm ci va chercher @lrvo/core et les modules @lrvo/module-* sur le registre privé. Sans le token du .npmrc, il échoue avec un 404.

Par défaut, il n'y a rien à faire ici : le CLI d'installation laisse le .npmrc suivi par git, donc le serveur le reçoit avec le clone. Voir Secrets et git.

Si le .npmrc a été sorti de git, il faut le déposer sur la machine de build avant l'installation :

npm login --registry=https://registry.lrvo.app/
npx lrvo-key
npm ci
npm run build

Ou, en CI, déposer ce .npmrc à la racine du projet et fournir le token dans la variable d'environnement LRVO_NPM_TOKEN, depuis un secret :

@lrvo:registry=https://registry.lrvo.app/
//registry.lrvo.app/:_authToken=${LRVO_NPM_TOKEN}
npm ci

${LRVO_NPM_TOKEN} s'écrit tel quel dans le fichier : npm le remplace par la valeur de la variable à la lecture du .npmrc. Le fichier ne contient donc aucun secret, quel que soit le shell de la machine de build.

Le token ne sert qu'à l'installation. Aucun code d'exécution ne le lit. Le fournir au démarrage de l'application ne sert donc à rien : il doit être présent avant le build.

Le token n'expire pas dans le temps. Voir lrvo-key.

2. Le build

npm run build

Le script est lrvo-modules sync && next build : la synchronisation des manifestes tourne juste avant, ce qui couvre les modules ajoutés, retirés ou mis à jour depuis le dernier déploiement.

3. Les variables de production

Le minimum :

NODE_ENV=production
NEXT_PUBLIC_URL=https://exemple.com
LRVO_NAME=Mon site
LRVO_DATABASE_URL=postgres://user:password@host:5432/prod

NEXT_PUBLIC_URL doit porter l'URL publique réelle. Elle sert à la vérification CSRF : une valeur incorrecte fait refuser toutes les requêtes mutantes, avec un symptôme trompeur de formulaire qui ne répond plus.

Ce qui change en production :

VariableEffet
NODE_ENV=productionLa base passe en TLS strict contre le magasin d'autorités du système.
LRVO_TRUST_PROXYNombre de reverse proxys devant l'application, pour que la limitation de débit voie l'IP réelle. Voir Le reverse proxy.
LRVO_DEVKITLaisser absent ou à false.

4. TLS de la base

Le défaut en production est strict. Si la base n'est joignable que par un réseau privé, avec un certificat auto-signé, deux options :

LRVO_DB_SSL_CA=/etc/ssl/certs/db-ca.pem   # préférable : chiffre et authentifie
LRVO_DB_SSL_NO_VERIFY=true                 # chiffre seulement

LRVO_DB_SSL_CA accepte un PEM inline ou un chemin de fichier.

Ne pas utiliser LRVO_DB_SSL_DISABLED=true en production : le trafic passerait en clair.

5. Le reverse proxy

Faire suivre les en-têtes d'origine, sinon la limitation de débit ne voit qu'une seule IP.

location / {
  proxy_pass http://127.0.0.1:3000;
  proxy_set_header Host              $host;
  proxy_set_header X-Real-IP         $remote_addr;
  proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
}

Puis déclarer côté application combien de proxys une requête traverse :

Devant l'applicationValeur
Aucun proxyLRVO_TRUST_PROXY=false
Un proxy : nginx, Caddy, ou Cloudflare relié directement à l'applicationLRVO_TRUST_PROXY=true, équivalent à 1
Deux proxys : Cloudflare, puis nginxLRVO_TRUST_PROXY=2

Ce nombre décide de l'entrée lue dans X-Forwarded-For. Chaque proxy ajoute à la fin de l'en-tête l'adresse qui vient de le joindre, et conserve ce que le client avait déjà écrit au début. Seules les dernières entrées sont donc dignes de confiance, une par proxy. Le core lit la N-ième en partant de la droite et ignore le reste, y compris la première, que le client choisit librement.

Le compte doit être exact. Trop bas, le core lit l'adresse du proxy amont : derrière Cloudflare puis nginx avec true, tous les visiteurs d'un même nœud Cloudflare partagent un compteur et se bloquent entre eux. Trop haut, il lit une entrée que le client a écrite, et la limitation se contourne.

L'application ne doit être joignable que par son proxy. Un client qui atteint directement le port de l'application, ou nginx sans passer par Cloudflare, écrit lui-même les entrées que le core croit ajoutées par un proxy. Écouter sur 127.0.0.1, et derrière Cloudflare n'ouvrir le pare-feu de l'origine qu'aux plages d'adresses de Cloudflare.

Ne pas activer cette variable sans proxy devant. Un client pourrait alors forger un X-Forwarded-For variable et contourner la limitation de débit.

6. Initialiser la base

npx lrvo-db init

À lancer une fois au premier déploiement. La commande est idempotente.

Aux déploiements suivants, migrate suffit et se contente de mettre le schéma à niveau :

npx lrvo-db migrate

Les deux commandes prennent un verrou consultatif : plusieurs répliques qui déploient en même temps se sérialisent au lieu de se marcher dessus.

Ne jamais lancer npx lrvo-db drop en production.

7. Vérifier

VérificationAttendu
GET /lrvo/api/healthRéponse de succès.
/auth/loginPage servie.
ConnexionAboutit, cookie posé.
/adminAccessible avec un compte admin.
Un formulaire d'adminEnregistre. Un échec pointe vers NEXT_PUBLIC_URL.
Journaux du démarrageAucun avertissement de variable requise absente.

Multi-instance

Deux comportements changent avec plusieurs instances.

Les tâches planifiées s'exécutent partout. Chaque instance a son propre registre cron : un job horaire tourne une fois par instance. Une tâche qui ne doit s'exécuter qu'une fois doit poser un verrou en base. Voir Planifier des tâches.

La limitation de débit est locale au processus. Les compteurs vivent en mémoire : la limite effective est multipliée par le nombre d'instances. Pour une limitation réellement partagée, il faut un magasin atomique externe. Voir Rate limit.

Sauvegardes

Sauvegarder la base et LRVO_ENCRYPTION_KEY, séparément. Une sauvegarde sans la clé est inexploitable pour les colonnes chiffrées, et il n'existe pas de récupération possible. Tester une restauration au moins une fois.

Mettre à jour

npx lrvo-update

Elle monte le core et les modules ensemble, affiche ce qui change, puis enchaîne la synchronisation des manifestes, les migrations et le diagnostic. Voir Mettre à jour un projet.

Une version majeure signale un changement cassant. Lire la note de version, livrée dans node_modules/@lrvo/core/CHANGELOG.md, et vérifier en particulier le retrait éventuel d'un sous-chemin de package.json#exports, qui casse au build. Voir Publication.

Gardes d'intégration continue

Trois commandes n'écrivent rien et sortent en code 1 quand une intervention est nécessaire.

npx lrvo-update --check   # une mise à jour LRVO est disponible
npx lrvo-doctor           # un constat est bloquant
npx lrvo-db status        # une migration est en attente

lrvo-db status avant un déploiement dit si migrate aura quelque chose à faire.

Sur cette page