Variables d'environnement
Le backend forge-api se configure par variables d'environnement. Il lit le
fichier .env au démarrage avec dotenvy, puis lit les variables du processus.
Ce chapitre liste les variables que le code lit réellement, avec leur défaut
quand il existe. Il ne liste pas les 2 992 lignes du fichier modèle .env.example
(mesure du 2026-10-03 : wc -l .env.example) : la plupart concernent des
outils tiers et des connecteurs, pas le backend.
Règle de lecture. Une variable citée ici est lue par le code ; le fichier est indiqué quand il importe. Ce chapitre n'est pas exhaustif : il omet des options réservées à un module précis. Pour savoir si une variable est lue :
grep -rn "NOM_DE_LA_VARIABLE" crates/*/src.
Priorité
- Les variables du processus (celles que pose le lanceur,
podmanou la session) priment.dotenvyne remplace jamais une variable déjà définie. - Le fichier
.envdu répertoire courant complète ce qui manque. - Les valeurs par défaut compilées dans le code s'appliquent en dernier.
Le code ne charge aucun fichier .env.staging ni .env.production. Pour un
autre environnement, posez les variables dans le processus.
Les secrets de production ne sont pas dans le dépôt. Sur chaque hôte, un script d'initialisation génère les fichiers d'environnement sur la machine cible, avec des permissions restreintes, et n'imprime jamais les valeurs (script d'initialisation des secrets de l'hôte). OpenBao peut en plus surcharger des secrets au démarrage (voir la section « Secrets externes (OpenBao) » plus bas).
Pour générer un secret : openssl rand -hex 32.
Variables exigées au démarrage
Si l'une d'elles manque, forge-api s'arrête avec le code 1
(contrôle de démarrage du code).
| Variable | Rôle | Règle |
|---|---|---|
DATABASE_URL | URL PostgreSQL | Obligatoire |
REDIS_URL | URL Valkey (compatible Redis) | Obligatoire. VALKEY_URL, si elle existe, est lue en premier pour la connexion |
JWT_SECRET | Secret de signature des jetons (HS256) | 32 caractères au moins, ni valeur par défaut connue, ni gabarit (change_me, replace_me, entre autres) |
Serveur HTTP
| Variable | Rôle | Défaut |
|---|---|---|
PORT | Port d'écoute | 3000 |
HOST | Adresse d'écoute (BIND_ADDRESS en repli) | toutes les interfaces |
APP_URL | URL publique de l'application | http://localhost:8008 (défaut de forge-core, port historique : l'API écoute sur 3000) |
CORS_ORIGINS | Origines autorisées, séparées par des virgules | http://localhost:8080, :8081, :8082 |
COOKIE_DOMAIN | Domaine des cookies de session en production | vide |
FORGE_MAX_BODY_BYTES | Taille maximale d'un corps de requête | 2 Mio |
FORGE_MAX_UPLOAD_BYTES | Taille maximale d'un envoi multipart | 25 Mio |
CSP_HEADER, HSTS_HEADER | Remplacent les en-têtes Content-Security-Policy et Strict-Transport-Security | valeurs du code |
Journalisation
| Variable | Rôle | Défaut |
|---|---|---|
RUST_LOG | Filtre tracing-subscriber | info,forge_api=debug,forge_mcp=debug quand la variable est absente ou invalide |
LOG_FORMAT | pretty ou compact : sortie lisible. Toute autre valeur : JSON | JSON |
TRACING_JSON, posée dans podman-compose.yml, n'est lue que par
forge_core::observability::init_tracing, que forge-api n'appelle pas : il
appelle sa propre fonction init_tracing (crates/forge-api/src/main.rs). Elle
ne change donc rien au format des journaux de forge-api.
Voir Journaux.
Authentification
| Variable | Rôle | Défaut |
|---|---|---|
JWT_EXPIRY | Durée du jeton d'accès : 7d, 24h, 30m, 3600s ou un nombre de secondes | 7 jours |
JWT_EXPIRY_SECS | Alias en secondes, lu si JWT_EXPIRY est absente ou illisible | 7 jours |
FORCE_2FA | Impose un second facteur à la connexion par mot de passe (true ou 1) : code TOTP si le compte l'a enrôlé, sinon code envoyé par e-mail | true |
FORGE_MFA_TOTP_REQUIRED | 1 ou true : refuse la connexion d'un compte sans TOTP enrôlé, pour tous les comptes | désactivé |
FORGE_MFA_REQUIRED_ROLES | Rôles séparés par des virgules (par exemple admin,owner) : même refus, pour ces rôles seulement | vide |
FORGE_PQC_ENABLED | 1 ajoute une signature ML-DSA-65 au jeton de session, en plus de HS256 | désactivé |
NODE_ENV, ENVIRONMENT, RUST_ENV, APP_ENV | Déclarent l'environnement. development, dev, local ou test déclarent un développement | absent = posture production |
FORGE_DEV | 1, true ou yes déclare un développement | absent |
Le silence ne relâche aucune garde : sans déclaration explicite de
développement, forge-api applique la posture production.
Les deux réglages FORGE_MFA_* sont lus par la connexion par mot de passe. Un compte créé par le SSO n'a pas de
second facteur applicatif : Authentik le porte en amont.
Le code de vérification envoyé par e-mail et le jeton intermédiaire du second facteur vivent quelques minutes dans Valkey (valeur fixe dans le code).
Clés de durcissement
| Variable | Rôle | Règle |
|---|---|---|
AT_REST_ENCRYPTION_KEY | Racine du chiffrement des secrets stockés (TOTP, identifiants de connecteurs, SSO) | Distincte de JWT_SECRET. Sans elle, le code retombe sur JWT_SECRET |
AUDIT_SIGNING_KEY | Signature de la chaîne d'audit | Sans elle, la chaîne n'est pas signée |
FORGE_STRICT_SECRETS | 1 rend les deux clés ci-dessus obligatoires | Sans cette variable, leur absence est un avertissement |
FORGE_TENANT_STRICT | 1 active le cloisonnement strict par organisation | Obligatoire hors développement déclaré, sinon arrêt au démarrage |
FORGE_MULTI_TENANT_STRICT | Désactive l'hydratation globale des identifiants de connecteurs | Posée sur les hôtes de production |
PHI_AT_REST_KEY | Clé de 64 caractères hexadécimaux pour le chiffrement des données de santé | Obligatoire en production, tolérée absente en développement déclaré |
PHI_AT_REST_KEY_PREVIOUS | Ancienne clé, lue en repli pendant une rotation | Optionnelle |
EXPORT_SEAL_KEY | Scellement des exports | Optionnelle. Absente : l'export scellé est indisponible |
Détails : Sécurité.
Limiteurs de débit (connexion)
| Variable | Rôle | Défaut |
|---|---|---|
ACCOUNT_HASH_SALT | Sel du hachage d'identité par compte | vide. Vide = limiteur par compte désactivé |
ACCOUNT_RATE_LIMIT_FAILURES_BLOCK | Échecs avant blocage du compte | défaut du code, non publié |
ACCOUNT_RATE_LIMIT_WINDOW_SECS | Fenêtre de comptage | défaut du code, non publié |
ACCOUNT_RATE_LIMIT_BLOCK_SECS | Durée du blocage | défaut du code, non publié |
AUTH_RATE_LIMIT_FAILURES_BACKOFF | Échecs par IP avant ralentissement | défaut du code, non publié |
AUTH_RATE_LIMIT_FAILURES_BLOCK | Échecs par IP avant blocage | défaut du code, non publié |
AUTH_RATE_LIMIT_BLOCK_DURATION_SECS | Durée du blocage par IP | défaut du code, non publié |
AUTH_RATE_LIMIT_WHITELIST | IP exemptées du seau par IP, séparées par des virgules | vide |
Sources : les deux limiteurs de connexion du code.
Purges planifiées
Ces purges sont actives par défaut. Une variable à 0 (ou false) suspend la
purge concernée.
| Variable | Rôle | Défaut |
|---|---|---|
RETENTION_SWEEP_ENABLED | Purge des journaux vocaux expirés | active |
RETENTION_SWEEP_HOURS | Cadence de cette purge | 24 |
RETENTION_VOICE_DAYS | Durée de conservation des journaux vocaux | 90 |
BACKUP_RETENTION_SWEEP_ENABLED | Purge des travaux de sauvegarde terminés | active |
BACKUP_RETENTION_DAYS | Durée de conservation des sauvegardes, en repli du réglage par cible de sauvegarde | 30 |
ACCOUNT_PURGE_ENABLED | Effacement définitif des comptes en attente de suppression | active |
Sources : crates/forge-api/src/routes/retention_worker.rs,
routes/backup_retention/mod.rs, routes/account_purge_worker.rs et
crates/forge-api/src/main.rs (lancement des trois planificateurs).
Messagerie (SMTP)
| Variable | Rôle | Défaut |
|---|---|---|
SMTP_HOST | Serveur SMTP | localhost |
SMTP_PORT | Port | 587 |
SMTP_USER | Compte authentifié. C'est aussi l'adresse expéditrice | aucun |
SMTP_PASSWORD | Mot de passe du compte | aucun |
SMTP_SECURE | true pour une connexion TLS directe | false |
EMAIL_FROM, EMAIL_FROM_NAME | Expéditeur de repli et nom affiché | nom : Chatbotaurus |
L'expéditeur est toujours le compte authentifié SMTP_USER : un From différent
casse l'alignement SPF et DKIM (crates/forge-core/src/email/mod.rs). Il n'existe
pas de variable SMTP_SKIP.
Authentification unique (Authentik, OIDC avec PKCE)
La route GET /api/v1/auth/oidc/login lit ces variables :
| Variable | Rôle | Défaut |
|---|---|---|
AUTHENTIK_SERVER_URL | Adresse du serveur Authentik | aucun : absente, la route répond 503 SSO_UNAVAILABLE |
AUTHENTIK_CLIENT_ID | Identifiant du client OIDC | aucun : même réponse 503 |
AUTHENTIK_CLIENT_SECRET | Secret du client OIDC | aucun : même réponse 503 |
AUTHENTIK_REDIRECT_URI | URL de retour enregistrée chez Authentik | http://localhost:8008/api/v1/auth/oidc/callback, défaut de développement : posez-la toujours |
OIDC_ALLOW_UNVERIFIED_EMAIL | 1 ou true accepte un fournisseur qui n'émet pas email_verified | refus |
La route de retour du backend est GET /api/v1/auth/oidc/callback
(crates/forge-api/src/router.rs).
ForgeConfig lit aussi SSO_AUTHENTIK_ENABLED, AUTHENTIK_SLUG,
AUTHENTIK_CALLBACK_URL, AUTHENTIK_LOGOUT_URL et AUTHENTIK_ROLE_MAPPING
(crates/forge-core/src/config.rs, bloc authentik). Mesure du 2026-10-03 :
aucun code hors de config.rs ne consomme ces champs (grep -rn "\.sso\." crates/*/src ne rend rien en dehors de ce fichier). Ils n'ont donc aucun effet
sur la connexion SSO aujourd'hui.
Modèles de langage (Ollama)
| Variable | Rôle | Défaut |
|---|---|---|
OLLAMA_BASE_URL | Adresse d'Ollama | http://localhost:11434 |
OLLAMA_MODEL | Modèle de génération | ministral-3:3b dans la configuration ; ministral-3:3b-instruct dans l'orchestrateur (OLLAMA_DEFAULT_MODEL en repli) |
OLLAMA_EMBEDDING_MODEL | Modèle d'embeddings du client Ollama. Le pipeline RAG n'en dépend pas : il vectorise en local avec fastembed (voir EMBEDDING_MODEL) | paraphrase-multilingual-MiniLM-L12-v2 |
OLLAMA_TIMEOUT_SECS | Délai d'une requête (configuration) | 120 |
OLLAMA_MAX_RETRIES | Nouvelles tentatives | 2 |
OLLAMA_TEMPERATURE | Température (orchestrateur) | 0,5 |
OLLAMA_MAX_TOKENS | Longueur maximale de réponse (orchestrateur) | 800 |
La liste des modèles souverains (crates/forge-core/src/model_governance.rs)
nomme cas/eurollm-1.7b-instruct-q8 (rôle Main, réservé à la traduction : le
code précise qu'il ne sert jamais à l'appel d'outil), ministral-3:3b (repli
de génération, et défaut de OLLAMA_MODEL) et l'embedder ci-dessus. Aucun
défaut du code ne désigne un fournisseur hors UE.
Recherche vectorielle et RAG
| Variable | Rôle | Défaut |
|---|---|---|
QDRANT_URL | Adresse gRPC de Qdrant | http://localhost:6334 |
QDRANT_HOST | Adresse REST utilisée par la sonde de santé | dérivée de QDRANT_URL |
QDRANT_API_KEY | Clé d'API | aucune |
QDRANT_COLLECTION_PREFIX | Préfixe des collections | forge |
EMBEDDING_MODEL | Modèle fastembed du pipeline RAG : multilingual (ou variable absente) donne paraphrase-multilingual-MiniLM-L12-v2, 384 dimensions (crates/forge-core/src/rag/embedder.rs) | multilingual |
QDRANT_VECTOR_SIZE | Dimension des vecteurs | 768 dans la configuration, 384 à la création des collections au démarrage |
RAG_CHUNK_SIZE, RAG_CHUNK_OVERLAP | Découpage des documents | 512 et 64 |
RAG_TOP_K, RAG_SCORE_THRESHOLD | Passages retenus et seuil | 5 et 0,7 |
ANTI_HALLUCINATION_THRESHOLD | Seuil de la garde anti-hallucination | 0,75 |
L'embedder du pipeline produit des vecteurs de 384 dimensions. Si vous
posez QDRANT_VECTOR_SIZE, posez 384 : une collection créée avec une autre
dimension refuse chaque insertion (crates/forge-api/src/main.rs).
Secrets externes (OpenBao)
OpenBao est facultatif. Si BAO_ADDR est posée, il surcharge les secrets
d'exécution au démarrage ; sinon les secrets viennent de l'environnement.
| Variable | Rôle | Défaut |
|---|---|---|
BAO_ADDR | Adresse du serveur | absente : OpenBao désactivé |
BAO_TOKEN | Jeton d'accès | aucun |
BAO_KV_MOUNT | Point de montage KV v2 | secret |
BAO_KV_PREFIX | Préfixe sous le montage | chatbotaurus |
BAO_NAMESPACE | Espace de noms | aucun |
BAO_TIMEOUT_SECS | Délai HTTP | 10 |
BAO_AUDIT_REQUIRED | Vrai : le démarrage est refusé si aucun périphérique d'audit n'est actif côté coffre | faux |
BAO_CACERT, BAO_CLIENT_CERT, BAO_CLIENT_KEY | TLS mutuel | aucun |
Voix
| Variable | Rôle | Défaut |
|---|---|---|
STT_PROVIDER | Moteur de transcription : speaches, kyutai ou mistral | speaches |
STT_ENDPOINT | Adresse du moteur de transcription | à définir (voir le paragraphe sous le tableau) |
STT_MODEL | Modèle de transcription | Systran/faster-whisper-large-v3 |
STT_LANGUAGE | Langue | fr |
STT_API_KEY | Clé d'API du moteur de transcription | aucune |
TTS_PROVIDER | Moteur de synthèse | kokoro |
TTS_ENDPOINT | Adresse du moteur de synthèse | à définir |
TTS_ENDPOINT_SPEACHES | Adresse du service qui sert l'allemand | absente : service non déployé |
Les défauts de STT_ENDPOINT et TTS_ENDPOINT dans le code sont des adresses
publiques qui ne servent rien. Définissez toujours ces deux variables. Le code
refuse un point d'accès hors UE.
Supervision
| Variable | Rôle | Défaut |
|---|---|---|
PROMETHEUS_BEARER_TOKEN | Jeton d'accès au point /metrics | absent : session plateforme élevée exigée |
FORGE_SIEM_ENABLED | 1 exporte la chaîne d'audit vers VictoriaLogs | désactivé |
FORGE_SIEM_URL | Adresse de VictoriaLogs | http://localhost:9428 |
Voir Supervision.
Connecteurs
CONNECTOR_CATALOGUE_DIR désigne le dossier des manifestes ; le défaut est
./connectors (crates/forge-api/src/main.rs).
Les fichiers connectors/*.yaml interpolent l'environnement avec
${VARIABLE:-défaut} (valeur de repli) ou ${VARIABLE:?message} (la valeur
vaut une chaîne vide si la variable est absente ; le message n'est qu'une
indication et n'arrête pas le chargement). Chaque
connecteur déclare ses propres variables ; pour Odoo : ODOO_URL,
ODOO_DATABASE, ODOO_USERNAME, ODOO_API_KEY. Voir
Fichiers de configuration.
Frontend (forge-ui)
Le frontend est une application wasm : elle ne lit aucune variable
d'environnement dans le navigateur. En web, elle appelle le chemin relatif
/api/v1 du même domaine. Sur les cibles natives, l'adresse de l'API se fixe à
la compilation avec API_URL ; le défaut est http://localhost:3000/api/v1
(crates/forge-ui/src/config/api.rs).
Voir aussi
- Fichiers de configuration — quels fichiers le code lit et dans quel ordre ils s'appliquent
- Sécurité — ce que chaque clé de durcissement protège, fichier par fichier
- Déploiement avec Podman — où les secrets de production naissent et comment les plans démarrent
- OpenBao et secrets — surcharge des secrets au démarrage et audit de lecture du coffre
- Problèmes connus — JWT invalide, CSRF refusé, configuration du frontend ignorée