Production
Cette page traite de la mise en production d'une instance : comment la placer correctement derrière un reverse proxy, ce que signifie l'invariant de l'instance unique et comment la sauvegarder. Notarium se déploie sous forme d'un conteneur unique — la configuration de production se résume aux trois points ci-dessous.
Reverse proxy et en-têtes forwarded
Vous placez un reverse proxy (nginx, Caddy, Traefik) devant l'application — il termine le TLS et relaie vers le port de Notarium. L'exigence clé : le proxy doit transmettre les en-têtes décrivant l'adresse externe.
Le reverse proxy doit envoyer X-Forwarded-Host (ou laisser Host intact) et X-Forwarded-Proto: https. Sinon, les mutations authentifiées par cookie depuis l'interface sont rejetées comme cross-origin — le symptôme est « je le vois mais je ne peux pas enregistrer ». La transmission de X-Forwarded-Proto est également nécessaire pour que le cookie de session reçoive le drapeau Secure.
Voici pourquoi : lors des mutations, le contrôle d'Origin compare la source de la requête à l'adresse que voit le navigateur — et cette adresse arrive dans un en-tête forwarded. Les appels d'agents via un PAT Bearer sont dispensés de ce contrôle (ils ne portent aucun cookie — donc aucune surface CSRF). Le proxy, quant à lui, doit écraser les en-têtes forwarded avec ses propres valeurs, et non laisser passer tels quels ceux du client.
Si vous activez l'autorisation OAuth pour les agents, définissez PUBLIC_BASE_URL lorsque vous êtes derrière le proxy (par exemple, https://notes.example.com) — une adresse externe stable pour les métadonnées OAuth. Sans elle, l'adresse est déduite des en-têtes forwarded. Voir Configuration.
La confiance envers l'adresse IP du client
Un axe distinct de celui de l'adresse : la véritable adresse IP du client. Deux limites se comptent par IP : les tentatives de connexion et l'admission de nouveaux clients OAuth. Derrière un proxy, toutes les requêtes arrivent de la même adresse ; sans configuration explicite, ces limites se compteraient donc par proxy — c'est-à-dire pour tout le monde à la fois.
Le réglage s'appelle TRUST_PROXY : la liste, séparée par des virgules, des IP/CIDR des proxys immédiats.
# .env — mettez l'adresse de votre propre conteneur proxy ou de votre hôte
TRUST_PROXY=172.18.0.0/16
Le défaut sûr, c'est de laisser la variable non définie : X-Forwarded-For n'a alors aucune incidence sur les limites, et aucun en-tête ne permet d'usurper l'IP d'autrui. Ne la définissez que si vous connaissez l'adresse de votre proxy avec certitude, et gardez la liste aussi restreinte que possible.
Les valeurs booléennes, les nombres de sauts, les plages nommées et les plages couvrant toutes les adresses (/0) sont rejetés au démarrage. Faire confiance à toutes les adresses reviendrait à laisser n'importe quel client s'attribuer une IP par en-tête et contourner la limite de connexion.
Ce réglage n'a aucun effet sur la transmission de X-Forwarded-Host et X-Forwarded-Proto — ce sont des axes indépendants, et le contrat de la section précédente reste inchangé.
L'invariant de l'instance unique
Notarium est conçu pour un processus unique. Deux états d'authentification vivent dans la mémoire du processus :
- la limite de tentatives de connexion — les compteurs de tentatives ;
- le registre des sockets SSE — le mécanisme par lequel la révocation d'un accès coupe instantanément les connexions actives.
Derrière un répartiteur de charge avec plusieurs instances et sans stockage partagé, ces mécanismes s'effondrent : un attaquant multiplie la limite par le nombre d'instances, et révoquer un accès sur une instance ne fermera pas une connexion SSE maintenue ouverte sur une autre.
Les deux états vivent dans la mémoire du processus ; c'est pourquoi, derrière un répartiteur de charge avec plusieurs instances et sans stockage partagé, ces mécanismes ne fonctionnent pas. Déplacer la base de métadonnées vers Postgres vous donne un état partagé, mais cela seul ne suffit pas pour la mise à l'échelle horizontale. Gardez une seule instance.
Sauvegardes
La sauvegarde canonique est une commande intégrée à l'image, et non une copie des fichiers effectuée de l'extérieur : notarium backup assemble une archive ZIP vérifiée et la renvoie en flux pendant que le service continue de tourner.
docker compose exec -T notarium backup > notarium-$(date -u +%Y%m%dT%H%M%SZ).zip
docker compose exec -T notarium backup verify < notarium-20260731.zip
La vérification doit faire partie de la tâche régulière, et non d'un geste ponctuel : elle ne modifie rien et détecte la corruption avant le jour où l'archive vous sera nécessaire. Pour la tâche elle-même, une simple redirection ne suffit pas — reprenez la séquence de publication sûre (fichier temporaire → synchronisation sur disque → lien physique atomique) décrite dans le runbook : Sauvegarde et restauration. Cette page couvre également la restauration dans un volume vierge et les limites d'applicabilité de la commande.
meta.db à chaudcp /data/meta.db, ou la copie du volume pendant que le service tourne, n'est pas une sauvegarde : la base de métadonnées fonctionne en mode WAL, des lignes déjà validées peuvent encore se trouver dans meta.db-wal, et des fichiers copiés un à un ne forment pas un instantané pris à un même instant.
Ce qui entre dans la sauvegarde, et pourquoi :
| Quoi | Rôle |
|---|---|
/data/spaces | Vos fichiers Markdown — la source de vérité. |
/data/meta.db | La base de métadonnées (historique, utilisateurs, accès) — irrécupérable à partir des fichiers. |
/data/jobs | Les artefacts et les téléversements des tâches d'import/export. |
/data/engine | Les index dérivés du moteur. Absents de l'archive : ils se reconstruisent à partir des fichiers. |
Si la base de métadonnées a été déplacée vers Postgres, ou si les notes résident hors de la racine des données, la commande intégrée s'arrête sur une erreur plutôt que de produire une archive partielle — sauvegardez alors la base et les répertoires montés avec les outils standard de votre fournisseur. Pour savoir précisément ce que contient la base de métadonnées, voir la page Base de données.