Auto-hébergement
Une image, deux variables, votre Postgres.
Voici le résumé dont un exploitant a besoin avant le premier démarrage. docs/self-hosting.md, dans le dépôt, est la version longue — la table de routage, votre propre proxy en frontal, et chaque symptôme en entier.
Ce qui est livré
Une image contient le front, l'API et un proxy qui route entre les deux, sur une seule origine, en linux/amd64 et linux/arm64. Pas de second conteneur à monter ni de maillage de services à décrire : ce qu'un navigateur atteint est un port.
Postgres n'y est pas, délibérément. Un conteneur qui possède vos données est un conteneur qu'on ne redémarre pas sans y penser, et toute plateforme sur laquelle il vaut la peine de déployer a déjà un Postgres managé que vous préférerez. docker/docker-compose.yml en livre un à côté de l'image pour le cas où vous n'en avez aucun.
Préparer la base
Kanso crée ses propres tables — Flyway tourne au démarrage, à chaque démarrage, et un unique conteneur applicatif signifie qu'il n'y a rien à coordonner. Ce qu'il ne peut pas créer, c'est le rôle, la base et une extension :
CREATE DATABASE kanso;
CREATE USER kanso WITH PASSWORD '…';
\c kanso
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- superuser
GRANT ALL ON SCHEMA public TO kanso; -- Flyway creates the tables
pg_trgm est la ligne qui échoue sur une instance managée. Une migration lance elle-même CREATE EXTENSION IF NOT EXISTS pg_trgm : sur un Postgres où le rôle kanso est superutilisateur, vous pouvez la sauter. Sur une instance managée, il ne l'est en général pas : RDS, Supabase et Neon l'autorisent tous, un cluster d'entreprise verrouillé demande en général qu'un DBA passe cette seule ligne. Le symptôme est le conteneur qui sort pendant Flyway avec permission denied to create extension "pg_trgm".
Postgres 16 est ce qui est testé. Tout ce qui a pg_trgm et un dialecte JDBC assez récent fonctionnera ; rien dans le schéma n'est exotique.
L'environnement
Deux variables sont requises, et tout le reste a une valeur par défaut défendable ou s'en déduit.
- KANSO_PUBLIC_URL
- Requise. L'URL à laquelle un navigateur atteint cette instance, schéma compris. La politique CORS, la vérification de la poignée de main WebSocket et chaque URI de redirection OAuth s'en déduisent — c'est pourquoi une erreur ici se manifeste par trois symptômes qui n'ont l'air d'avoir aucun rapport.
- SPRING_DATASOURCE_URL
- Requise, avec
_USERNAMEet_PASSWORD. L'hôte est résolu depuis l'intérieur du conteneur : un nom de service sous Compose,host.docker.internalpour un Postgres sur cette machine mais hors de Docker, et jamaislocalhost. - KANSO_TLS
autoouoff. Vautautopar défaut quand l'URL publique est enhttps:— voir plus bas.- KANSO_SECRET_KEY
- La clé AES qui chiffre les secrets stockés par l'assistant d'installation. Générée dans le volume au premier démarrage si elle n'est pas posée. La poser explicitement est la moitié de ce qui rend le conteneur sans état.
- KANSO_AUTH_MODE
devfait venir l'identité d'un en-têteX-Kanso-Usernon vérifié. Ce mode existe pour les tests et la CI, doit être demandé explicitement, journalise un avertissement bruyant et désactive entièrement la porte des agents. N'exposez jamais une instance qui tourne ainsi.
Tout le reste de ce que Kanso lit — NOTION_*, GOOGLE_*, GITHUB_*, les réglages de webhooks et de limitation — est optionnel et passe tel quel. Ce qui est posé ici l'emporte sur l'assistant d'installation et s'y affiche en lecture seule.
TLS, et qui est le frontal
auto — le Caddy embarqué obtient et renouvelle un certificat Let's Encrypt pour l'hôte de l'URL publique. Le port 80 doit être joignable depuis l'internet public pour le défi, pas seulement le 443. C'est la bonne réponse si le frontal n'est pas par ailleurs sous votre contrôle.
off — votre propre proxy termine TLS et Kanso sert du HTTP en clair derrière. L'URL publique dit toujours https://… : elle décrit ce qu'emploie le navigateur, pas ce que le conteneur écoute.
Sous off, X-Forwarded-For devient votre affaire. Caddy préserve l'en-tête entrant tel quel, puisque votre proxy est le frontal — c'est donc à votre proxy de supprimer tout en-tête qu'il n'a pas posé lui-même, faute de quoi un client peut déclarer sa propre adresse. Sous auto, Caddy est le frontal et l'écarte pour vous.
Ce que contient /data, et ce qu'il faut sauvegarder
Deux choses qui doivent survivre à un redémarrage. Rien d'autre — tickets, documents et sessions sont tous dans Postgres.
- /data/secret.key
- La clé AES qui chiffre le jeton Notion et les secrets de client OAuth stockés par l'assistant. La perdre oblige à ressaisir ces secrets.
- L'état ACME de Caddy
- Le certificat et la clé de compte, sous
KANSO_TLS=auto. Le perdre fait redemander un certificat à Let's Encrypt à chaque redémarrage.
Le conteneur est sans état — aucun volume — quand vous posez KANSO_SECRET_KEY explicitement et tournez en KANSO_TLS=off. Les deux raisons d'avoir /data disparaissent, et il reste une image et deux variables d'environnement, c'est-à-dire la forme qu'attendent ECS, Fly ou un Deployment Kubernetes. Visez cela si vous en avez un.
Une sauvegarde, c'est donc : votre Postgres, et soit /data/secret.key, soit la valeur de KANSO_SECRET_KEY gardée là où vous gardez vos secrets.
L'exploitation
Mettre à jour, c'est tirer une image plus récente et la redémarrer. Flyway tourne à chaque démarrage et fait avancer le schéma ; pas d'étape de migration séparée à retenir, et pas de fenêtre de maintenance à déclarer pour un seul conteneur applicatif.
Les sessions sont en mémoire : plus d'une instance d'API demande un stockage de sessions partagé — une propriété, avec spring-session-jdbc. D'ici là, n'en faites tourner qu'une.
/actuator/health répond sur la vivacité, la disponibilité et la vérification de la base : c'est ce que doit viser la sonde de santé d'une plateforme. Le point d'entrée sonde aussi l'hôte de la base avant de démarrer la JVM et sort en une dizaine de secondes avec un message nommant ce qu'il n'a pas pu atteindre, au lieu d'échouer une minute plus tard au fond d'une trace.
Quand ça ne démarre pas
- Sort en une seconde
KANSO_PUBLIC_URL is not set. Le message dit quoi poser.- Sort en dix secondes
cannot reach …— le point d'entrée a sondé l'hôte de la base et n'a rien eu. Sous Compose, cet hôte est le nom du service ; hors de Docker sur cette machine, c'esthost.docker.internal, jamaislocalhost.- Sort pendant Flyway
password authentication failedveut dire que l'hôte a répondu : l'URL est bonne, les identifiants non.permission denied to create extension, c'estpg_trgm, plus haut.- Connecté, mais rien ne se met à jour seul
- La poignée de main WebSocket a été refusée. L'en-tête
Originest comparé à l'URL publique exactement — même cause qu'une connexion Google renvoyantredirect_uri_mismatch, et le plus souvent un proxy qui n'envoie pasX-Forwarded-Proto: https. - Pas de certificat sous auto
- Le port 80 doit être joignable depuis l'internet public pour le défi ACME, pas seulement le 443.
Le conteneur affiche, sur une ligne et avant tout le reste, l'adresse sur laquelle Caddy s'est lié et le KANSO_TLS qu'il a résolu : c'est la première chose à lire quand le symptôme est ambigu.