Kanso Documentation

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 _USERNAME et _PASSWORD. L'hôte est résolu depuis l'intérieur du conteneur : un nom de service sous Compose, host.docker.internal pour un Postgres sur cette machine mais hors de Docker, et jamais localhost.
KANSO_TLS
auto ou off. Vaut auto par défaut quand l'URL publique est en https: — 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
dev fait venir l'identité d'un en-tête X-Kanso-User non 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'est host.docker.internal, jamais localhost.
Sort pendant Flyway
password authentication failed veut dire que l'hôte a répondu : l'URL est bonne, les identifiants non. permission denied to create extension, c'est pg_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 Origin est comparé à l'URL publique exactement — même cause qu'une connexion Google renvoyant redirect_uri_mismatch, et le plus souvent un proxy qui n'envoie pas X-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.