Déploiement

Le Labo du Yeti est conçu pour un déploiement une instance = un client sur un VPS Plesk (Linux). Le serveur Node tourne en permanence, expose une API sur un port interne, et Plesk fait office de reverse proxy HTTPS. Ce guide couvre l'installation complète, du clone Git au premier compte owner.

Modèle SaaS hybride. Chaque client a son propre dépôt cloné, sa propre base SQLite, son propre JWT_SECRET, son propre domaine. Aucune donnée n'est mutualisée entre clients. La mise à jour se fait par git pull manuel ou via un tag de release.

1. Prérequis serveur

Le CMS est volontairement léger en dépendances système. Une instance fonctionne sur un VPS partagé Plesk modeste (1 vCPU, 1 Go RAM, 10 Go SSD) pour un site jusqu'à quelques milliers de pages générées.

1.1 Logiciels requis

ComposantVersionNotes
Node.js22 LTSObligatoire. Plesk fournit Node 22 via /opt/plesk/node/22/. better-sqlite3 dispose de prebuilds pour Node 22 → pas de compilation native.
npm10+Livré avec Node 22. Sur Plesk, accessible via /opt/plesk/node/22/bin/npm.
SQLiteintégréAucune installation séparée. better-sqlite3 embarque le moteur. Mode WAL activé au boot.
Git2.30+Pour cloner et mettre à jour le dépôt.
SMTPoptionnelRecommandé pour 2FA email, reset password et notifications cocon. Voir Réglages SMTP.

1.2 Dimensionnement indicatif

2. Variables d'environnement (.env)

Le fichier .env à la racine du projet pilote toute la configuration sensible. Sur Plesk, il est préférable de déclarer ces variables dans le panel Node.js (section Variables d'environnement) plutôt que de committer un fichier — Plesk les injecte au démarrage du process.

Anti-pattern critique. Ne jamais committer .env dans Git. Le .gitignore du projet l'exclut explicitement. Un JWT_SECRET qui fuit = tous les comptes admins compromis.

2.1 Variables disponibles

VariableObligatoireValeur par défaut / exempleRôle
PORTrecommandé3001Port d'écoute du serveur Node. Plesk proxifie ce port en HTTPS.
NODE_ENVouiproductionDésactive les logs verbeux, active les caches, force le mode strict d'Express.
JWT_SECRETouichaîne ≥ 24 caractèresClé de signature des JWT. Doit être unique par instance. Voir génération ci-dessous.
JWT_EXPIRES_INnon7dDurée de vie des tokens JWT. Format ms (1h, 30m, 7d).
CORS_ORIGINouihttps://client.exemple.comDomaine front autorisé. Peut être une liste séparée par virgules.
SMTP_HOSToptionnelsmtp.mailgun.orgServeur SMTP pour 2FA, reset password, notifications cocon.
SMTP_PORToptionnel587Port SMTP. 465 pour TLS direct, 587 pour STARTTLS.
SMTP_USERoptionnelcompte SMTPIdentifiant SMTP.
SMTP_PASSoptionnelmot de passe SMTPMot de passe ou clé d'app SMTP.
SMTP_FROMoptionnel"CMS <no-reply@client.com>"Expéditeur des emails sortants.
NPM_BINPlesk/opt/plesk/node/22/bin/npmChemin absolu vers npm. Utilisé par le loader d'extensions quand npm n'est pas dans le PATH du process Node Plesk.

2.2 Génération d'un JWT_SECRET fort

Le secret JWT doit être imprévisible. La commande Node ci-dessous génère une chaîne hex de 96 caractères (48 octets aléatoires) :

node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"

Copier la sortie dans JWT_SECRET. Un secret de moins de 24 caractères fait échouer le démarrage avec une erreur explicite dans les logs : le serveur refuse de démarrer en mode NODE_ENV=production avec un secret faible.

2.3 Exemple .env minimal

PORT=3001
NODE_ENV=production
JWT_SECRET=a7f3b9c1d8e2f4a6b9c3d1e5f7a9b2c4d6e8f1a3b5c7d9e2f4a6b8c1d3e5f7a9b2c4d6e8f1a3b5c7d9
JWT_EXPIRES_IN=7d
CORS_ORIGIN=https://client.exemple.com

# SMTP (recommandé)
SMTP_HOST=smtp.mailgun.org
SMTP_PORT=587
SMTP_USER=postmaster@mg.client.exemple.com
SMTP_PASS=xxxxxxxxxxxxxxxx
SMTP_FROM="Le Labo du Yeti <no-reply@client.exemple.com>"

# Plesk uniquement, si extensions npm install échoue
NPM_BIN=/opt/plesk/node/22/bin/npm

3. Setup Plesk pas à pas

Plesk gère le reverse proxy HTTPS, le process Node (démarrage / redémarrage automatique), et l'injection des variables d'environnement. Voici la procédure complète.

3.1 Créer le domaine

  1. Dans Plesk, Sites Web et DomainesAjouter un domaine.
  2. Saisir le nom de domaine (ex. client.exemple.com) et créer un utilisateur FTP/SSH dédié.
  3. Activer le SSL (Let's Encrypt) dès la création — Plesk renouvelle automatiquement le certificat.
  4. Activer la redirection HTTPS forcée dans Hébergement & DNS.

3.2 Cloner le dépôt

Via SSH ou l'extension Git de Plesk, cloner le dépôt dans le répertoire du domaine :

cd /var/www/vhosts/client.exemple.com/
git clone https://github.com/ton-org/cms-ia.git httpdocs-app
cd httpdocs-app
Important : le frontend buildé est commité. Le dossier frontend/dist/ fait partie du dépôt (voir commit "Add frontend/dist build + update gitignore for Plesk deploy"). Plesk ne fait pas de build npm à l'install — la RAM des hébergements partagés ne suffit pas pour vite build. Le build est fait en local ou en CI, puis commité.

3.3 Configurer le Document Root

Le serveur Node compile les pages statiques dans public/. Plesk doit pointer son Document Root sur ce sous-dossier — pas sur la racine du projet. Cela isole le code source des fichiers servis publiquement.

  1. Sites Web et Domaines → ton domaine → Paramètres d'hébergement.
  2. Répertoire racine du document : /httpdocs-app/public (ou le chemin équivalent selon ton clone).
  3. Sauvegarder.
Pourquoi ce choix ? Si Document Root pointait à la racine du projet, n'importe qui pourrait télécharger .env, content/cms.db, ou les sources backend en tapant l'URL. Avec public/ comme racine, seuls les fichiers compilés et la médiathèque sont exposés.

3.4 Activer Node.js

  1. Onglet Node.js du domaine (extension Plesk).
  2. Version Node.js : 22.x LTS.
  3. Mode applicatif : production.
  4. Racine de l'application : /httpdocs-app (racine du clone, pas public/).
  5. URL applicative : laisser le défaut (Plesk gère le proxy).
  6. Fichier de démarrage de l'application : backend/src/server.js.

3.5 Installer les dépendances

Dans le panneau Node.js de Plesk, cliquer sur NPM install. Plesk lance npm install --omit=dev dans la racine de l'application. La commande compile better-sqlite3 (prebuild Node 22, pas de compilation native si Node 22 est correctement détecté), sharp, bcrypt.

Si NPM install échoue (cas observé sur certaines installations Plesk où le PATH du process Node ne contient pas npm), définir NPM_BIN=/opt/plesk/node/22/bin/npm dans les variables d'environnement Plesk puis relancer. Le loader d'extensions utilise cette variable pour exécuter npm install dans les sous-dossiers d'extensions sans dépendre du PATH. Voir le commit "Fix(extensions): résoudre npm via sibling de node (Plesk-safe)".

3.6 Déclarer les variables d'environnement

Dans le panneau Node.js, section Variables d'environnement personnalisées, ajouter une à une les variables du .env (cf. section 2.3). Plesk les injectera au démarrage. Ne pas committer .env.

3.7 Démarrer / redémarrer l'application

Cliquer sur Redémarrer l'application dans le panel Node. Vérifier les logs (Logs dans le panel Node) — le démarrage normal affiche :

[boot] SQLite WAL ready
[boot] stores seeded
[boot] extensions loaded: hello-world
[boot] server listening on :3001
[boot] CORS allowed: https://client.exemple.com

4. Premier accès et bootstrap

À l'installation initiale, la base est vide : aucun utilisateur, aucune page. Le CMS détecte cet état et bascule en mode bootstrap, qui force la création du premier compte owner.

4.1 Accéder à l'admin

Visiter https://client.exemple.com/admin. La SPA React détecte l'absence d'utilisateurs (via GET /api/auth/status qui retourne needs_bootstrap: true) et affiche l'écran Bootstrap au lieu du login.

4.2 Créer le premier owner

L'écran demande : nom complet, username, email, mot de passe (8 caractères minimum, avec majuscule + chiffre). À la validation, l'API POST /api/auth/bootstrap crée le compte et lui attribue automatiquement le rôle owner — c'est le seul rôle capable de modifier les paramètres Sécurité et de promouvoir d'autres utilisateurs.

Une seule fenêtre. Le bootstrap n'est accessible qu'une fois. Dès qu'un utilisateur existe, l'endpoint POST /api/auth/bootstrap retourne 403. Pour créer un second owner, se connecter en tant que owner et utiliser Réglages → Administrateurs → Ajouter.

4.3 Configurer SMTP (recommandé immédiatement)

Une fois connecté, aller dans Réglages → Général → SMTP et renseigner les identifiants. Le bouton Tester l'envoi envoie un email de test à l'adresse du compte courant. Sans SMTP, la 2FA email est désactivée, et les rappels cocon vers admin / webmaster ne partent pas.

4.4 Activer le mode production

Dans Réglages → Sécurité (accessible uniquement au owner), basculer Mode de development à production. Cela :

Pré-requis. SMTP doit être fonctionnel avant de passer en mode production, sinon plus personne ne peut se connecter (le code 2FA ne part jamais). Toujours tester un envoi SMTP réussi avant de basculer.

5. Sauvegarde et restauration

Toutes les données utilisateur tiennent dans trois emplacements : content/cms.db (base SQLite), uploads/ (médias), extensions/installed/ (extensions installées par l'utilisateur). Le CMS offre deux mécanismes de backup.

5.1 Backup via l'UI

Dans Réglages → Sécurité → Sauvegardes, le bouton Exporter le site (.zip) génère un ZIP contenant la DB (checkpointée en WAL TRUNCATE avant export), les médias, et les extensions. Téléchargement direct. Réservé au rôle owner.

Le bouton Restaurer depuis un .zip remplace l'état courant par le contenu du ZIP. Avant chaque restore, un safety backup automatique est créé dans backups/safety/ côté serveur — récupérable en cas de mauvaise manipulation. Rate-limité à 1 restauration par minute pour éviter les accidents.

5.2 Backup côté Plesk

En complément, configurer une sauvegarde Plesk hebdomadaire qui inclut le dossier complet de l'application. Cela couvre aussi les variables d'environnement et la configuration Node Plesk.

6. CI/CD et mises à jour

6.1 Workflow manuel : git pull + restart

Le workflow le plus simple pour mettre à jour une instance :

# Via SSH
cd /var/www/vhosts/client.exemple.com/httpdocs-app
git pull origin main
# Si dépendances modifiées : NPM install via le panel Plesk
# Sinon : juste Redémarrer l'application via le panel Plesk

Ou tout faire depuis Plesk : extension GitTirer maintenant, puis Node.jsRedémarrer l'application.

6.2 Données préservées par git pull

Le .gitignore exclut toutes les données utilisateur — un git pull ne peut pas écraser :

6.3 Pipeline GitHub Actions (roadmap)

Un workflow build-release.yml est planifié (cf. Roadmap) pour automatiser :

  1. npm ci dans frontend/ et backend/ ;
  2. vite buildfrontend/dist/ ;
  3. commit + push de frontend/dist/ sur une branche release ;
  4. tag semver pour suivi des versions clients.

Les instances Plesk pourront alors git pull origin release au lieu de main, garantissant un frontend testé et buildé.

7. Checklist de mise en production

À cocher avant d'annoncer le site comme livré :

  1. Node 22 LTS sélectionné dans le panel Plesk.
  2. Document Root pointe sur public/, pas sur la racine.
  3. SSL Let's Encrypt actif et HTTPS forcé.
  4. JWT_SECRET unique, généré via crypto.randomBytes(48), jamais commité.
  5. CORS_ORIGIN renseigné avec le domaine exact (pas de wildcard).
  6. NODE_ENV=production dans les variables Plesk.
  7. SMTP configuré et testé depuis l'UI.
  8. Premier owner créé via le bootstrap (compte personnel, pas générique).
  9. Mode production activé dans Réglages → Sécurité (2FA forcée).
  10. Backup Plesk hebdo programmé.
  11. Au moins un export ZIP manuel téléchargé et archivé hors-serveur.
  12. Logs Plesk Node vérifiés sans erreur au démarrage.
  13. Test complet : connexion, création page, build, vue publique du site.

8. Dépannage Plesk-specific

SymptômeCause probableSolution
npm install échoue depuis l'UI extensionsPATH du process Node ne contient pas npmAjouter NPM_BIN=/opt/plesk/node/22/bin/npm dans les variables Plesk.
better-sqlite3 erreur NODE_MODULE_VERSION mismatchModules compilés pour une autre version de NodeSupprimer node_modules/ et relancer NPM install avec Node 22 sélectionné.
404 sur /adminDocument Root pointé à la racine au lieu de public/Corriger le Document Root dans Paramètres d'hébergement.
CORS bloque le frontendCORS_ORIGIN manquant ou incorrectVérifier la valeur exacte du domaine (avec https://, sans slash final).
2FA jamais reçue après bascule productionSMTP non configuré ou identifiants invalidesBloquer en SSH, repasser auth.security.mode = development dans la DB, retester SMTP.
App ne redémarre pas après git pullPlesk ne détecte pas le changement de fichierCliquer manuellement Redémarrer l'application dans le panel Node.

Pour les anti-patterns à éviter en production (auto-pull main, build frontend sur Plesk, etc.), consulter la page Anti-patterns. Pour le détail des paramètres de sécurité, voir Sécurité.