Aller au contenu

Configuration

Xolo se configure entièrement par variables d'environnement, préfixées XOLO_. Le fichier .env.dist du dépôt sert de modèle de référence pour un déploiement depuis les sources ; en Docker, passez ces mêmes variables avec -e ou un fichier d'environnement.

Secret et session

Variable Défaut Description
XOLO_SECRET_KEY (requis) Clé hexadécimale de 32 octets utilisée pour chiffrer les clés API des fournisseurs (AES-GCM). Générez-la avec openssl rand -hex 32. Le serveur refuse de démarrer si elle est absente.
XOLO_HTTP_SESSION_KEYS (vide) Liste de clés séparées par des virgules, utilisées pour signer/chiffrer les cookies de session. Vide, chaque processus tire une clé aléatoire : les sessions ne survivent alors ni à un redémarrage ni au passage d'un réplica à l'autre.
XOLO_HTTP_SESSION_COOKIE_MAX_AGE 24h Durée de vie d'un cookie de session, et de la session OIDC qu'il désigne. Doit être strictement positive : le serveur refuse de démarrer sinon.

HTTP

Variable Défaut Description
XOLO_HTTP_ADDRESS :3002 Adresse d'écoute du serveur.
XOLO_HTTP_BASE_URL / URL publique de l'instance (utilisée pour construire les liens absolus, les redirections OIDC…).
XOLO_HTTP_SHUTDOWN_TIMEOUT 30s Délai d'arrêt gracieux : sur SIGTERM/SIGINT le serveur cesse d'accepter des connexions puis laisse ce délai aux requêtes en cours (complétions streamées comprises) avant de les couper. Le délai de grâce du conteneur (stop_grace_period Docker, TimeoutStopSec systemd) doit lui être supérieur.
XOLO_HTTP_SESSION_COOKIE_SECURE false Passez à true derrière HTTPS.
XOLO_HTTP_RATE_LIMIT_* — Limitation de débit HTTP par IP.

Authentification

Xolo authentifie les utilisateurs via un ou plusieurs fournisseurs OAuth2/OIDC. Au moins un doit être configuré.

Variable Description
XOLO_HTTP_AUTHN_DEFAULT_ADMINS Emails (séparés par des virgules) promus administrateurs plateforme dès leur première connexion.
XOLO_HTTP_AUTHN_ACTIVE_BY_DEFAULT Si true, les nouveaux comptes sont actifs sans validation manuelle.
XOLO_HTTP_AUTHN_AUTO_CREATE_USERS Si true (défaut), une identité inconnue obtient un compte à sa première connexion. Si false, seules les identités pré-provisionnées peuvent se connecter — à trois exceptions près : les adresses de DEFAULT_ADMINS, les applications, et les adresses destinataires d'une invitation ciblée en attente. Un membre provisionné se connecte dans tous les cas, par son identité déclarée ou par un email vérifié qui ne désigne que lui (voir Provisioning).
XOLO_HTTP_AUTHN_PROVIDERS_GOOGLE_KEY / _SECRET Fournisseur Google OAuth2.
XOLO_HTTP_AUTHN_PROVIDERS_GITHUB_KEY / _SECRET Fournisseur GitHub OAuth2.
XOLO_HTTP_AUTHN_PROVIDERS_GITEA_KEY / _SECRET / _AUTH_URL / _TOKEN_URL / _PROFILE_URL / _DISCOVERY_URL Fournisseur Gitea auto-hébergé. DISCOVERY_URL est optionnel : sans lui, le fournisseur démarre avec un avertissement et le login interactif retombe sur AUTH_URL / TOKEN_URL ; avec lui, sa politique de validation est celle des fournisseurs OIDC nommés. DISCOVERY_URL seul, ou AUTH_URL + TOKEN_URL (avec éventuellement PROFILE_URL), doivent être renseignés : un fournisseur configuré avec uniquement KEY et SECRET est refusé au démarrage.

Fournisseurs OIDC nommés

Pour un ou plusieurs fournisseurs OIDC génériques (Auth0, Keycloak, Authelia…), listez leurs identifiants puis configurez chacun sous un préfixe dédié :

XOLO_HTTP_AUTHN_OIDC_PROVIDERS=keycloak,auth0

XOLO_HTTP_AUTHN_OIDC_PROVIDER_KEYCLOAK_DISCOVERY_URL=https://idp.example.com/.well-known/openid-configuration
XOLO_HTTP_AUTHN_OIDC_PROVIDER_KEYCLOAK_KEY=xolo
XOLO_HTTP_AUTHN_OIDC_PROVIDER_KEYCLOAK_SECRET=change-me
XOLO_HTTP_AUTHN_OIDC_PROVIDER_KEYCLOAK_LABEL="Mon SSO"
XOLO_HTTP_AUTHN_OIDC_PROVIDER_KEYCLOAK_SCOPES=openid,profile,email

L'URL de découverte est obligatoire. Xolo télécharge le document au démarrage, avec un délai maximal de 10 secondes. Si le document est inaccessible ou incomplet, le serveur refuse de démarrer, en mode mono-tenant comme en multi-tenant. Le document doit contenir issuer, authorization_endpoint et token_endpoint. Chacun de ces champs, ainsi que userinfo_endpoint, introspection_endpoint et end_session_endpoint quand ils sont présents, doit être une URL absolue en http ou https.

Le champ jwks_uri n'est pas obligatoire : un IdP non conforme peut démarrer sans bloquer l'instance. Dans ce cas, Xolo émet un avertissement au démarrage qui cite le fournisseur concerné et indique que la validation JWT des ID Tokens est désactivée pour ce fournisseur. La validation d'introspection et de UserInfo reste active : le fournisseur reste enregistré dans la liste interne avec un JWKSURL vide, oidctoken ignore ce fournisseur (errInvalidToken, que la boucle d'authentification passe), tandis que oauth2token valide les jetons opaques via l'introspection_endpoint ou, à défaut, l'userinfo_endpoint documenté. C'est le cas type d'un IdP qui émet des jetons opaques validés par introspection — voir l'issue #27.

Pour valider des jetons d'accès opaques côté API (introspection RFC 7662, ou UserInfo à défaut) plutôt que des ID Tokens OIDC autoportés, activez XOLO_HTTP_AUTHN_OAUTH2TOKEN_ENABLED=true.

Un ID Token présenté à l'API (en-tête Authorization: Bearer ou cookie, oidctoken) est accepté par défaut quelle que soit son audience, pourvu qu'il soit signé par l'émetteur du fournisseur. Quand plusieurs applications partagent le même fournisseur, restreignez les audiences acceptées :

XOLO_HTTP_AUTHN_OIDC_PROVIDER_KEYCLOAK_ALLOWED_AUDIENCES=xolo,mon-frontend

Le claim aud du jeton doit alors contenir au moins une de ces valeurs, sinon le jeton est refusé (401). Si un jeton désigne une clé (kid) absente du JWKS en cache, Xolo recharge le JWKS une fois, au plus une fois par minute et par fournisseur, pour suivre une rotation de clés sans redémarrage.

Fournisseur Gitea

Le fournisseur Gitea est aligné sur les fournisseurs OIDC nommés dès que XOLO_HTTP_AUTHN_PROVIDERS_GITEA_DISCOVERY_URL est configuré : le document téléchargé doit alors contenir issuer, authorization_endpoint et token_endpoint. Si le document est inaccessible, mal formé ou incomplet, le serveur refuse de démarrer.

XOLO_HTTP_AUTHN_PROVIDERS_GITEA_DISCOVERY_URL est cependant optionnel : sans lui, Xolo démarre avec un avertissement de démarrage, et le login interactif utilise directement les champs AUTH_URL / TOKEN_URL / PROFILE_URL configurés. Lorsque DISCOVERY_URL est configuré et que le document est validé, ses authorization_endpoint et token_endpoint priment toujours sur la configuration statique : validateOIDCDiscovery exige que ces deux champs soient présents et absolus, donc la branche statique n'est consultée que sur le chemin DISCOVERY_URL vide (que la validation préalable refuse si AUTH_URL ou TOKEN_URL manquent). Pour PROFILE_URL, le document de découverte tient lieu de repli lorsqu'il publie un userinfo_endpoint et que le champ statique est vide ; avec DISCOVERY_URL, si PROFILE_URL est vide et que le document ne publie pas userinfo_endpoint, le fournisseur refuse de démarrer avec un message explicite plutôt que d'échouer à la première connexion.

Sur le chemin statique (DISCOVERY_URL vide), PROFILE_URL est également obligatoire : sans lui, aucun userinfo_endpoint n'est disponible en repli et la première connexion échouerait avec une erreur goth opaque. Le serveur refuse alors de démarrer avec le message gitea provider requires PROFILE_URL or a discovery document that publishes userinfo_endpoint, aligné sur le comportement de la branche découverte.

Qu'il passe par la découverte ou par la configuration statique, un fournisseur Gitea a besoin d'au moins un de ces deux chemins :

  • DISCOVERY_URL renseigné et résolu (avec un document complet),
  • AUTH_URL et TOKEN_URL renseignés (avec éventuellement PROFILE_URL).

Un fournisseur configuré avec uniquement KEY / SECRET est refusé au démarrage avec l'erreur gitea provider requires either DISCOVERY_URL or both AUTH_URL and TOKEN_URL. C'est un changement de comportement par rapport aux versions précédentes, qui acceptaient ce mode et échouaient à la première connexion ; l'erreur explicite permet aujourd'hui de repérer la mauvaise configuration dès le boot.

Comme pour les fournisseurs OIDC nommés, jwks_uri est optionnel : en son absence, ou lorsqu'il est présent mais mal formé (URL relative, scheme non http(s)), un avertissement est émis au démarrage et la validation JWT des ID Tokens est désactivée pour ce fournisseur — l'introspection reste active si le document la publie.

Sessions OIDC et déconnexion back-channel

Une connexion interactive par un fournisseur OAuth2/OIDC ouvre une session enregistrée en base ; le cookie ne porte que son identifiant. Chaque requête vérifie la session par une simple lecture : un cookie copié ne survit pas à la déconnexion, et une session reste valide après un redémarrage et d'un réplica à l'autre, pourvu que tous partagent XOLO_HTTP_SESSION_KEYS. Une session expire au bout de XOLO_HTTP_SESSION_COOKIE_MAX_AGE. Les sessions expirées et les entrées devenues inutiles sont supprimées toutes les 10 minutes par chaque réplica.

Un navigateur non authentifié qui demande une page de l'interface y revient après la connexion. Si un seul fournisseur interactif est configuré, il y est envoyé directement, sans page de choix : avec une session déjà ouverte chez le fournisseur, la connexion se fait sans interaction. Pour éviter une boucle si la connexion échoue, ce saut n'a lieu qu'une fois toutes les 30 secondes (cookie xolo_auto_sign_in) ; sinon la page de connexion s'affiche.

Une connexion doit commencer chez Xolo (/auth/oidc/providers/{fournisseur}) et revenir sur le même navigateur dans les 15 minutes. Une connexion initiée par le fournisseur d'identité, ou un retour sans le cookie posé au départ, échoue avec sign-in start missing dans le journal ; l'utilisateur doit relancer la connexion depuis Xolo.

Un fournisseur OIDC peut en outre révoquer les sessions par OpenID Connect Back-Channel Logout. Déclarez auprès de lui l'URL :

https://{hôte}/auth/oidc/providers/{fournisseur}/backchannel-logout
  • Seuls les fournisseurs dont l'émetteur est prouvé, avec un identifiant client et un jwks_uri valide, l'acceptent : fournisseurs OIDC nommés, Gitea avec DISCOVERY_URL et Google. Les autres répondent 404.
  • Le logout_token doit être signé (RS256, RS384 ou RS512) par l'émetteur, destiné à l'identifiant client, et contenir sub et jti. La révocation porte sur le sujet : toutes les sessions de cet émetteur et de ce sujet sont fermées, dans tous les tenants, et une connexion commencée avant la révocation est refusée. Un jeton ne portant qu'un sid est refusé (400).
  • Un jeton n'est accepté que dans les 5 minutes qui suivent son émission. Un jeton déjà traité répond 200 sans effet, ce qui permet au fournisseur de réessayer. Les horloges des réplicas et du fournisseur doivent concorder à 5 minutes près.
  • En multi-tenant, n'importe quel domaine actif convient : la révocation vaut pour tous les tenants. La route n'est pas soumise à la limitation de débit par IP, chaque requête étant authentifiée par son jeton signé.
  • Le compteur xolo_oidc_backchannel_logouts_total suit les résultats (revoked, replayed, invalid, unavailable).

La déconnexion durable ne couvre que ces sessions interactives. Les autres modes d'authentification gardent leur propre mécanisme :

Mode Fin de validité
ID Token OIDC présenté à l'API (oidctoken) Son exp, prolongé de XOLO_HTTP_AUTHN_OIDCTOKEN_EXPIRY_LEEWAY. Une déconnexion ne le révoque pas.
Jeton d'accès opaque (oauth2token) Révoqué chez le fournisseur, il reste accepté jusqu'à l'expiration du cache de validation (XOLO_HTTP_AUTHN_OAUTH2TOKEN_CACHE_TTL, 60 s par défaut).
Session ouverte par /auth/token/login Son cookie, pendant XOLO_HTTP_SESSION_COOKIE_MAX_AGE. Le jeton API n'est pas revérifié pendant la session.

La déconnexion locale (/auth/oidc/logout) ferme la session Xolo ; elle ne ferme pas la session ouverte chez le fournisseur d'identité.

Stockage

Variable Défaut Description
XOLO_STORAGE_AUTO_MIGRATE true Applique les migrations au démarrage. Avec false, vérifie seulement le schéma et refuse les migrations en attente. Voir la procédure UUID, qui impose l’arrêt de tous les anciens réplicas.
XOLO_STORAGE_DATABASE_DSN data.sqlite Base de données. Un DSN commençant par postgres:// (ou une chaîne libpq host=… dbname=…) cible PostgreSQL ; toute autre valeur est interprétée comme un chemin de fichier SQLite.
XOLO_STORAGE_DATABASE_POOL_MAX_OPEN_CONNS 25 Connexions ouvertes maximum. Sur SQLite, les écritures passent par une seule connexion et ce pool ne sert que les lectures.
XOLO_STORAGE_DATABASE_POOL_MAX_IDLE_CONNS 5 Connexions inactives conservées dans le pool (le pool de lecture sur SQLite).
XOLO_STORAGE_DATABASE_POOL_CONN_MAX_LIFETIME 60m Durée de vie maximale d'une connexion (du pool de lecture sur SQLite).
XOLO_STORAGE_DATABASE_CACHE_USERS_* / _PROVIDERS_* — Taille et TTL des caches en mémoire pour les utilisateurs et fournisseurs (activés par défaut, 25 entrées, 60 min).
XOLO_STORAGE_DATABASE_CACHE_QUOTA_ENABLED true Réutilise les totaux de dépense lus à chaque requête proxy pour la vérification des budgets, au lieu de les relire à chaque fois. Les totaux eux-mêmes viennent de compteurs journaliers tenus à l'enregistrement de l'usage, pas d'une agrégation de l'historique.
XOLO_STORAGE_DATABASE_CACHE_QUOTA_SIZE 4096 Nombre maximal de totaux conservés. Chaque organisation active en occupe trois (jour, mois, année), plus trois par utilisateur actif.
XOLO_STORAGE_DATABASE_CACHE_QUOTA_TTL 10s Durée de réutilisation d'un total. Les dépenses sont appliquées aux totaux en cache au fil des enregistrements, donc une instance seule reste exacte pendant toute la durée ; avec plusieurs instances, c'est le délai pendant lequel l'une peut ignorer la dépense d'une autre. 0 relit les compteurs à chaque vérification.

Choisir entre SQLite et PostgreSQL

SQLite reste le défaut : aucune dépendance externe, idéal pour une instance unique. La base y passe en mode WAL : les écritures sont sérialisées sur une connexion, les lectures servies en parallèle par un pool de connexions en lecture seule, si bien qu'un rapport long ne bloque pas le proxy. Une base en mémoire (:memory:) n'a pas de pool de lecture. PostgreSQL est recommandé dès que plusieurs instances de Xolo partagent le même stockage, ou lorsque le volume d'événements et d'enregistrements d'usage devient important.

XOLO_STORAGE_DATABASE_DSN="postgres://xolo:motdepasse@postgres:5432/xolo?sslmode=disable"

Le schéma est créé et migré automatiquement au démarrage. Il n'existe pas de migration automatique des données d'une base SQLite existante vers PostgreSQL : la bascule suppose une base neuve.

Plugins

Variable Défaut Description
XOLO_PLUGINS_DIR ./plugins Répertoire scanné au démarrage pour les binaires de plugins exécutables.
XOLO_PLUGINS_MEM_LIMIT (désactivé) Limite mémoire (GOMEMLIMIT) appliquée à chaque sous-processus plugin, ex. 512MiB.
XOLO_PLUGINS_RESTART_COOLDOWN 30s Délai minimum entre deux redémarrages d'un même plugin, pour éviter les redémarrages en boucle.

Proxy

Variable Défaut Description
XOLO_PROXY_UPSTREAM_TIMEOUT 5m Délai maximal accordé à un fournisseur. Pour une complétion non streamée ou un calcul d'embeddings, il borne l'appel complet, tentatives de retry comprises. Pour une complétion streamée, il borne l'attente du premier fragment puis le silence entre deux fragments, sans jamais couper une réponse longue qui continue d'arriver. À expiration le client reçoit une erreur 504 explicite au lieu d'une coupure opaque du reverse proxy. Le timeout du reverse proxy placé devant Xolo doit rester strictement supérieur à cette valeur. 0 désactive la borne.
XOLO_PROXY_ACTIVE_USER_CACHE_TTL 30s Durée de réutilisation du nombre d'utilisateurs actifs sur un forfait par abonnement, qui sert de dénominateur à la répartition entre utilisateurs. Ce comptage parcourt toute la fenêtre du forfait dans la table d'usage ; il est pris une fois par forfait et par fenêtre, partagé par tous ses utilisateurs, et une valeur expirée est servie telle quelle pendant qu'il est repris en arrière-plan. Une valeur ancienne peut manquer les utilisateurs qui ont consommé pour la première fois depuis qu'elle a été prise, ce qui élargit les parts dans la limite du budget du forfait. À augmenter quand la table d'usage est volumineuse. 0 recompte à chaque requête.
XOLO_PROXY_ACTIVE_USER_COUNT_TIMEOUT 10s Durée maximale d'un comptage d'utilisateurs actifs. Le comptage tourne indépendamment de la requête proxy qui l'a déclenché, et la première requête d'une fenêtre ne l'attend qu'une seconde avant de calculer sa part sur l'effectif complet. Au-delà de cette durée le comptage est abandonné, l'échec est mémorisé pour la durée du cache et la part de chaque utilisateur retombe sur l'effectif complet. Si le compteur xolo_fair_share_degraded_shares_total monte en continu, c'est ce délai qu'il faut relever, ou l'index de la table d'usage qu'il faut vérifier.

Événements

Variable Défaut Description
XOLO_EVENTS_MAX_PER_ORG 100000 Plafond global d'événements non épinglés conservés par organisation.
XOLO_EVENTS_DEFAULT_PER_ORG 10000 Rétention appliquée aux organisations sans réglage explicite (voir Paramètres).
XOLO_EVENTS_EVALUATION_INTERVAL 30s Fréquence d'évaluation des alertes.
XOLO_EVENTS_PURGE_INTERVAL 5m Fréquence de purge de la fenêtre glissante.

API de provisioning

Écouteur d'administration dédié, protégé par TLS mutuel. Voir API de provisioning.

Variable Défaut Description
XOLO_PROVISIONNING_API_ENABLED false Ouvre l'écouteur d'administration.
XOLO_PROVISIONNING_API_ADDRESS :3003 Adresse d'écoute.
XOLO_PROVISIONNING_API_TLS_CERT_FILE (requis si activé) Certificat serveur (PEM).
XOLO_PROVISIONNING_API_TLS_KEY_FILE (requis si activé) Clé privée du serveur (PEM).
XOLO_PROVISIONNING_API_TLS_CLIENT_CA_FILE (requis si activé) Autorité vérifiant les certificats clients.
XOLO_PROVISIONNING_API_SHUTDOWN_TIMEOUT 10s Délai d'arrêt gracieux.
XOLO_OWNERSHIP — Autorité d'écriture de chaque famille (famille=shared\|local\|control_plane, séparées par des virgules) ; les familles omises valent shared. Voir Autorité d'écriture.
XOLO_LIFECYCLE_ENABLED false Autorise l'enregistrement des suppressions, installe les protections des périmètres gelés et lance le worker de purge. Voir Cycle de vie.
XOLO_LIFECYCLE_RETENTION 720h Durée de gel d'une ressource supprimée avant sa purge, de 1 s à 3650 jours.
XOLO_LIFECYCLE_POLL_INTERVAL 1m Fréquence de recherche des suppressions à purger, de 1 s à 1 h.
XOLO_LIFECYCLE_PURGE_BATCH 1000 Lignes supprimées par transaction de purge, de 1 à 100 000.

Multi-tenant

Désactivé par défaut : l'instance possède un unique tenant default, créé par la migration et jamais exposé à ses utilisateurs — pas de sous-domaine, pas de changement d'URL. Une fois activé, le tenant est identifié par l'hôte de la requête : chaque nom d'hôte est un domaine déclaré par l'API de provisioning, et un hôte qui n'est le domaine actif d'aucun tenant actif répond 404 : un hôte inconnu ne doit pas révéler que l'instance existe.

Les tenants et leurs domaines se créent exclusivement par l'API de provisioning ; la création d'un second tenant répond 409 tant que XOLO_MULTITENANCY_ENABLED vaut false.

Variable Défaut Description
XOLO_MULTITENANCY_ENABLED false Active la résolution du tenant par domaine.
XOLO_MULTITENANCY_HOST_PATTERN — Mise à niveau uniquement. Gabarit d'hôte contenant exactement une fois le marqueur {tenant}, par exemple {tenant}.xolo.example.com, éventuellement suivi d'un port ignoré. Au premier démarrage multi-tenant, il est développé une seule fois en un domaine actif par tenant existant, puis ignoré. Le serveur refuse de démarrer s'il est mal formé.
XOLO_MULTITENANCY_DEFAULT_TENANT_SLUG default Tenant servi lorsque le multi-tenant est désactivé.

Conséquences sur la configuration HTTP

XOLO_HTTP_BASE_URL doit alors être absolue — schéma et hôte — sous peine de refus de démarrage. Elle n'est plus l'URL de l'instance mais le gabarit dont chaque domaine dérive la sienne : son schéma, son port et son chemin sont conservés, son hôte est remplacé par le domaine de la requête. Liens, redirections et URL de rappel OAuth restent ainsi sur le domaine du tenant, ce qui est nécessaire : le cookie de session est propre à un hôte et la session porte le tenant sur lequel elle a été ouverte.

L'URL de rappel à déclarer auprès du fournisseur d'identité varie donc par domaine :

https://{domaine}/auth/oidc/providers/{fournisseur}/callback

Un fournisseur acceptant un redirect_uri à joker (Keycloak, Authentik…) couvre tous les tenants d'une seule déclaration. Une OAuth App GitHub n'accepte qu'une URL de rappel unique et Google n'accepte que des URI exactes : ces deux fournisseurs imposent une déclaration par domaine, ce qui les rend impraticables au-delà de quelques tenants.

Prévoyez enfin le DNS et les certificats TLS de chaque domaine — un joker (*.xolo.example.com) si les domaines partagent un suffixe — sur le reverse proxy placé devant Xolo, et passez XOLO_HTTP_SESSION_COOKIE_SECURE=true.

Taux de change et tâches de fond

Variable Défaut Description
XOLO_EXCHANGE_RATE_PROVIDER frankfurter Source des taux de change (frankfurter ou file).
XOLO_EXCHANGE_RATE_TTL / _REFRESH_INTERVAL 24h Fraîcheur et fréquence de rafraîchissement des taux.
XOLO_TASK_RUNNER_URI memory://taskrunner?parallelism=5&cleanupInterval=10m&cleanupDelay=1h Configuration du planificateur de tâches de fond.
XOLO_LOGGER_LEVEL 0 Niveau de log (slog, valeurs négatives = debug). Au niveau 0 (info) seules les requêtes SQL en erreur ou lentes sont journalisées ; le niveau debug (-4) trace chaque requête SQL.

Vérification

Le fichier .env.dist à la racine du dépôt liste l'ensemble des variables avec leurs commentaires. En cas de configuration invalide (secret manquant, fournisseur OIDC mal formé…), xolo-server refuse de démarrer et affiche l'erreur en clair sur la sortie standard.