Title: Auto-h%C3%A9berger la stack LLM : Node et SQLite %E2%80%94 LLM EU Canonical: https://llmeu.com/fr/docs/self-hosting/ Markdown mirror: https://llmeu.com/fr/docs/self-hosting.md Machine-readable: https://llmeu.com/llms.txt (index) - https://llmeu.com/llms-full.txt (full catalogue) - https://llmeu.com/llms-catalogue.json Premiers pas - [D%C3%A9marrage rapide](/fr/docs/quickstart/) - [Console](/fr/docs/console/) - [Migration](/fr/docs/migration/) - [R%C3%A9f%C3%A9rence de l'API](/fr/docs/api/) R%C3%A9f%C3%A9rence - [Authentification](/fr/docs/authentication/) - [Points de terminaison](/fr/docs/endpoints/) - [Erreurs](/fr/docs/errors/) - [Limites de d%C3%A9bit](/fr/docs/rate-limits/) - [Streaming](/fr/docs/streaming/) - [Politiques](/fr/docs/policies/) - [Routage et politique](/fr/docs/routing/) - [R%C3%A9sidence et r%C3%A9gions](/fr/docs/residency/) - [Preuves et v%C3%A9rification](/fr/docs/evidence/) - [Compatibilit%C3%A9 OpenAI](/fr/docs/openai-compat/) Exploitation - [Auto-h%C3%A9bergement](/fr/docs/self-hosting/) # Auto-h%C3%A9bergement Node et un r%C3%A9pertoire inscriptible sont toute l'exigence. Les affirmations ci-dessous ont %C3%A9t%C3%A9 lues dans les fichiers nomm%C3%A9s %C3%A0 c%C3%B4t%C3%A9 ; tout ce qui n'a pas pu %C3%AAtre confirm%C3%A9 n'est pas ici. ## Points d'entr%C3%A9e - package.json exige Node >= 22.5. Le stockage SQLite est le module node:sqlite propre %C3%A0 Node. - Il n'y a aucune liste de d%C3%A9pendances : les applications, paquets, scripts et tests s'ex%C3%A9cutent sur la biblioth%C3%A8que standard de Node, et le Dockerfile n'installe rien. - Trois processus existent ; chacun ouvre la base de donn%C3%A9es et ex%C3%A9cute la migration au d%C3%A9marrage. ``` node apps/web/server/main.mjs # hub + console + embedded API API_EMBED=false node apps/api/src/main.mjs # API only, no pages node apps/worker/src/run.mjs # probes, latency, rollup, housekeeping ``` ## Datastore DATABASE_URL=sqlite:./data/llmeu.db ne n%C3%A9cessite aucun serveur, et le r%C3%A9pertoire et le fichier sont cr%C3%A9%C3%A9s %C3%A0 la premi%C3%A8re ouverture. Le handle fonctionne en mode WAL avec les cl%C3%A9s %C3%A9trang%C3%A8res activ%C3%A9es et un d%C3%A9lai d'attente occup%C3%A9 de 5 s. packages/shared/src/db/schema.sql est le sch%C3%A9ma. Il est en cr%C3%A9ation seule et idempotent, donc le r%C3%A9ex%C3%A9cuter est sans danger ; une colonne ajout%C3%A9e %C3%A0 une table existante doit aussi %C3%AAtre d%C3%A9clar%C3%A9e dans l'%C3%A9tape additive dans packages/shared/src/db/index.mjs. Une URL postgres:// emprunte une branche d'adaptateur s%C3%A9par%C3%A9e. Cette branche n%C3%A9cessite le paquet pg, qui n'est pas une d%C3%A9pendance d%C3%A9clar%C3%A9e, et l'en-t%C3%AAte de schema.sql indique de traiter le chemin Postgres comme non v%C3%A9rifi%C3%A9 jusqu'%C3%A0 ce qu'un vrai pilote et une migration test%C3%A9e existent. SQLite est le chemin que ce d%C3%A9p%C3%B4t ex%C3%A9cute. ## CLI op%C3%A9rateur node scripts/db.mjs lit DATABASE_URL et ne n%C3%A9cessite aucun service. Commandes : ## Environnement Regroup%C3%A9s comme .env.example les regroupe. ## Docker Compose et l'image sont facultatifs : la suite propre au d%C3%A9p%C3%B4t ne n%C3%A9cessite pas Docker, et le chemin principal est un processus local sans services. - Le profil par d%C3%A9faut ex%C3%A9cute web : ports 3000 et 8088, SQLite sur le volume llmeu-data %C3%A0 /app/data, l'API embarqu%C3%A9e, et un healthcheck sur /healthz. - La m%C3%AAme image ex%C3%A9cute le worker avec node apps/worker/src/run.mjs, en attendant que web devienne sain et en partageant le volume llmeu-data. - Deux profils suppl%C3%A9mentaires sont d%C3%A9sactiv%C3%A9s par d%C3%A9faut : postgres (postgres:16-alpine) et redis (redis:7-alpine, r%C3%A9serv%C3%A9 et non lu par le chemin de code v1). - Le profil gpu ex%C3%A9cute vllm/vllm-openai avec une r%C3%A9servation de p%C3%A9riph%C3%A9rique NVIDIA et monte les poids en lecture seule depuis l'h%C3%B4te ; il n'est pas activ%C3%A9 par d%C3%A9faut, car revendiquer une inf%C3%A9rence UE sans GPU serait faux. - Le Dockerfile est FROM node:24-alpine avec tini, sans %C3%A9tape de build ni installation de d%C3%A9pendances, s'ex%C3%A9cute en tant qu'utilisateur node, %C3%A9crit uniquement sous /app/data, expose 3000 et 8088, et d%C3%A9marre apps/web/server/main.mjs. ## Sauvegardes node scripts/backup.mjs sans options %C3%A9crit ./backups/llmeu- .db. SQLite est copi%C3%A9 avec VACUUM INTO, jamais cp, car une base de donn%C3%A9es WAL active copi%C3%A9e avec cp peut produire un %C3%A9tat d%C3%A9chir%C3%A9 ou obsol%C3%A8te. ``` node scripts/backup.mjs # ./backups/llmeu-.db node scripts/backup.mjs --out /srv/backups/ # explicit destination node scripts/backup.mjs --verify ./backups/llmeu-.db node scripts/backup.mjs --restore ./backups/llmeu-.db --yes node scripts/backup.mjs --list ``` Chaque sauvegarde SQLite est v%C3%A9rifi%C3%A9e avant que le script ne signale un succ%C3%A8s : elle est restaur%C3%A9e dans une copie temporaire, PRAGMA integrity_check doit retourner ok, le sch%C3%A9ma est r%C3%A9appliqu%C3%A9, et les nombres de lignes pour les mod%C3%A8les, les organisations et les utilisateurs sont affich%C3%A9s. Avec une URL postgres://, le script utilise pg_dump --format=custom et n%C3%A9cessite pg_dump dans le PATH ; un dump ne peut pas %C3%AAtre ouvert comme une base de donn%C3%A9es, donc ses nombres de lignes n%C3%A9cessitent une restauration scratch. ## Courriel Le courriel transactionnel %E2%80%94 r%C3%A9initialisation de mot de passe, v%C3%A9rification d'adresse, invitations %E2%80%94 utilise MAIL_SMTP_* ou MAIL_API_URL avec MAIL_FROM. Le transport est choisi une fois au d%C3%A9marrage et signal%C3%A9 sur chaque page qui n%C3%A9cessite du courriel. Un d%C3%A9ploiement sans l'un ni l'autre est un %C3%A9tat pris en charge : l'inscription, la connexion, le changement de mot de passe, les %C3%A9quipes et les invitations fonctionnent, mais le courriel de r%C3%A9initialisation de mot de passe et de v%C3%A9rification ne peut pas y %C3%AAtre trait%C3%A9. Les pages le disent, et node scripts/db.mjs passwd est la voie de r%C3%A9cup%C3%A9ration. ## Backends d'inf%C3%A9rence Une ligne de point de terminaison nomme un runtime et une r%C3%A9gion, et le registre de backends choisit l'adaptateur par r%C3%A9gion, donc un point de terminaison ne peut %C3%AAtre trait%C3%A9 que par une machine dans la r%C3%A9gion qu'il nomme. - INFERENCE_MOCK=true conserve le backend de d%C3%A9veloppement d%C3%A9terministe, qui n'a besoin ni de GPU ni de poids. - GPU_ENABLED=false exclut les backends g%C3%A9r%C3%A9s ; avec GPU_ENABLED=true, VLLM_BASE_URL s'applique %C3%A0 la seule r%C3%A9gion nomm%C3%A9e par VLLM_REGION. - Un d%C3%A9ploiement avec plusieurs r%C3%A9gions d%C3%A9finit une variable par r%C3%A9gion, nomm%C3%A9e d'apr%C3%A8s le slug de la r%C3%A9gion (par exemple VLLM_BASE_URL_DE_FRA). Un point de terminaison dans une r%C3%A9gion sans backend configur%C3%A9 est refus%C3%A9, plut%C3%B4t que servi depuis une machine dans une autre r%C3%A9gion. - Les backends partenaires proviennent de PARTNER_BASE_URL_ et prennent PARTNER_SOVEREIGNTY et PARTNER_API_KEY ; le serveur autorise l'utilisation de partenaires lorsque PARTNER_BASE_URL est d%C3%A9fini. Sans GPU configur%C3%A9, le backend de d%C3%A9veloppement d%C3%A9terministe r%C3%A9pond et sa sortie indique qu'aucun poids r%C3%A9el n'a %C3%A9t%C3%A9 ex%C3%A9cut%C3%A9 et que l'inf%C3%A9rence first-party n%C3%A9cessite VLLM_BASE_URL et le flag gpu_enabled. Un succ%C3%A8s de substitution qui semblerait r%C3%A9el serait la seule chose que ce produit ne doit jamais livrer.