---
title: "Installer Quire avec Docker Compose"
description: "Installez Quire sur votre propre infrastructure avec Docker Compose."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/fr/llms.txt
> Use this file to discover all available pages before exploring further.

# Installer Quire avec Docker Compose

<span id="installing-quire-with-docker-compose"></span>

Il s’agit du produit complet sur un seul hôte : le LMS, ses travaux d’arrière-plan, les services temps réel et d’édition collaborative, et tous les services facultatifs derrière un profil. La conception est décrite à la section 2 de `docs/architecture/23-ops.md`.

Autres cibles : [Vercel](/fr/ops/vercel/) et [Cloudflare Workers](/fr/ops/cloudflare/) n’exécutent que la couche Web. La mise à niveau est décrite dans [upgrade.md](/fr/ops/upgrade/), et les sauvegardes et le test de restauration dans [backup-restore.md](/fr/ops/backup-restore/).

## Prérequis <!--quire:what-you-need-->

- Docker Engine 27 ou ultérieur avec le plug-in Compose 2.30 ou ultérieur.
- 4 cœurs CPU et 8 Go de mémoire pour la pile par défaut ; 8 cœurs et 16 Go avec `--profile full` (ClamAV utilise à lui seul environ 1,5 Go pour ses signatures).
- Un nom DNS pour la couche Web et un autre pour le contenu non fiable. Il doit s’agir d’hôtes distincts : les paquets SCORM et le HTML téléversé s’exécutent depuis l’origine du contenu afin de ne jamais pouvoir lire les cookies du LMS.
- Pour un test local, `lvh.me` et `*.localhost` se résolvent en 127.0.0.1 ; c’est ce qu’utilise `docker/.env.example`. Le service `proxy` de la pile sert les deux en https avec une autorité de certification locale ; rien d’autre n’est donc à installer (voir « TLS »).
- Les ports 80 et 443 doivent être disponibles sur l’hôte (les variables `QUIRE_PROXY_HTTP_PORT` et `QUIRE_PROXY_HTTPS_PORT` permettent de les déplacer).

## Premier démarrage <!--quire:first-run-->

```sh
QUIRE_APP_ORIGIN=https://learn.example.org \
QUIRE_CONTENT_ORIGIN=https://content.example-content.org \
QUIRE_SETUP_ADMIN_EMAIL=you@example.org \
  docker/scripts/init-env.sh
docker compose -f docker/compose.yaml up -d --build
docker compose -f docker/compose.yaml logs init
```

`docker/scripts/init-env.sh` crée `docker/.env` à partir de `docker/.env.example`, en générant tous les secrets (mots de passe de base de données, clés de signature et clé principale, paire de clés de lancement du contenu) ainsi que la clé de signature des points de contrôle d’audit dans `docker/secrets/audit-signing-key.pem`, montée comme secret dans les workers par Compose. Le script nécessite uniquement `sh`, `awk` et `openssl`, et refuse d’écraser un fichier `docker/.env` existant. Copiez ces deux fichiers hors de l’hôte : sans `QUIRE_MASTER_KEY`, une base restaurée ne peut pas déchiffrer les identifiants enregistrés. Pour remplir le fichier manuellement, exécutez `cp docker/.env.example docker/.env` ; il décrit la génération de chaque secret.

Les deux origines doivent utiliser `https` : le service de contenu refuse le http simple en production, et elles ne doivent pas partager un même domaine enregistrable. Le service `proxy` termine TLS pour les deux (voir « TLS ») ; `init-env.sh` refuse une origine `http://`.

La pile démarre selon un ordre fixe ; chaque étape attend la précédente :

1. `postgres` devient sain. Lors du tout premier démarrage, son script d’initialisation (`docker/postgres/init/90-passwords.sh`) définit les mots de passe des quatre rôles.
2. `migrate` applique toutes les migrations et initialise la file de travaux dans la base de contrôle ainsi que dans chaque base dédiée de locataire, vérifie qu’elles sont toutes cohérentes, puis se termine (docs/ops/upgrade.md). Les migrations s’exécutent à chaque démarrage et sont idempotentes ; une mise à niveau consiste donc à déployer une nouvelle image et à redémarrer.
3. `init` (`apps/web/src/first-run.ts`) enregistre la base de données de l’application sous `QUIRE_DATABASE_ID` et, si `QUIRE_SETUP_ADMIN_EMAIL` est défini, crée la première organisation et son administrateur. L’adresse de connexion et le mot de passe généré ne sont affichés qu’une fois, dans `docker compose logs init`.
4. `web`, `content`, `worker`, `scheduler`, `collab` et `centrifugo` démarrent.
5. `proxy` démarre lorsque `web` et `content` sont sains.

Ouvrez `https://demo.` suivi du domaine de votre application (le journal `init` affiche l’adresse de connexion exacte), puis connectez-vous. Sur une installation locale, faites d’abord confiance à l’autorité de certification du proxy (voir « TLS »). Changez le mot de passe généré dans `/account/security`.

Un processus lancé sans un secret requis refuse de démarrer et indique le paramètre manquant dans son journal. Aucun service ne démarre avec une configuration incomplète.

## Services et profils <!--quire:services-and-profiles-->

| Service | Profil | Rôle |
| --- | --- | --- |
| postgres | toujours | Base de données (PostgreSQL 18 avec pgvector, construite depuis `docker/postgres.Dockerfile`), avec archivage du WAL dès le premier démarrage |
| migrate, init | toujours | Exécution ponctuelle : migrations, puis premier démarrage |
| web | toujours | LMS sur le port `QUIRE_HTTP_PORT` (8080) |
| content | toujours | Origine du contenu non fiable sur le port `QUIRE_CONTENT_PORT` (8081) |
| worker | toujours | Travaux d’arrière-plan : e-mails, rapports, traitement de fichiers et webhooks |
| scheduler | toujours | Travaux récurrents : enregistre les 64 planifications d’exécution et les transmet au worker ; un seul leader à la fois |
| collab | toujours | WebSocket d’édition collaborative sur le port `QUIRE_COLLAB_HTTP_PORT` (1234) |
| centrifugo | toujours | Diffusion temps réel sur le port `QUIRE_REALTIME_PORT` (8000) |
| proxy | toujours | Caddy, porte d’entrée TLS sur les ports 80 et 443 (voir « TLS ») |
| valkey | `cache` | Cache et limites de débit |
| clamav | `scan` | Analyse antivirus des téléversements |
| gotenberg | `preview` | Aperçus PDF des fichiers Office et rendu des certificats |
| imgproxy | `images` | Redimensionnement et conversion des images |
| transcoder | `video` | Image worker avec ffmpeg sous licence LGPL uniquement, pour les versions vidéo |
| seaweedfs | `storage` | Stockage d’objets compatible S3 sur cet hôte |
| otelcol | `observability` | Collecteur OpenTelemetry |
| mailpit | `devmail` | Intercepte tous les e-mails sortants pour tester Quire |
| backup | `backup` | Sauvegarde de base ponctuelle ; voir backup-restore.md |
| backup-scheduler, backup-offsite | `backup` | Sauvegarde de base toutes les `QUIRE_BACKUP_INTERVAL_HOURS` et copies chiffrées hors hôte avec test de vérification hebdomadaire |
| h5p | `h5p` | Image d’outil H5P LTI 1.3 fournie par vos soins dans `QUIRE_H5P_IMAGE`, sur le port `QUIRE_H5P_PORT` (8090) ; voir « Connecter un fournisseur H5P » |

`--profile full` démarre tous les services facultatifs sauf `backup` et `h5p`. Pour en démarrer un, exécutez `docker compose -f docker/compose.yaml --profile scan up -d`. Quire fonctionne aussi sans service facultatif et indique ce qui manque : sans antivirus, les fichiers sont stockés sans analyse et l’administrateur en est informé ; sans Gotenberg, les fichiers sont proposés au téléchargement plutôt qu’en aperçu ; sans transcodeur, les vidéos sont lues dans leur format d’origine.

Toutes les images tierces et leurs obligations de licence figurent dans `docker/third-party-containers.yaml`.

### Connecter un fournisseur H5P <!--quire:connecting-an-h5p-provider-->

Quire n’intègre ni ne fournit d’environnement d’exécution H5P ou de service associé (ADR 0019). Si vous utilisez H5P, souscrivez votre propre offre hébergée ou exploitez une instance H5P auto-hébergée séparément de Quire. Enregistrez ce fournisseur comme outil externe LTI 1.3, puis ajoutez son contenu aux cours sous forme d’activités outil. Quire échange les notes et la progression d’activité ou de correction via LTI Assignment and Grade Services (AGS). Si le fournisseur envoie également des déclarations xAPI, configurez cette fonction séparément pour le magasin de déclarations xAPI de Quire ; l’échange des notes et de la progression via AGS n’envoie pas de déclarations xAPI. Les activités H5P des cours Moodle importés sont signalées comme nécessitant une connexion à un outil LTI. Le fournisseur reste responsable de son environnement H5P, de la création de contenu, de sa banque de contenus et de l’historique des tentatives.

Pour exploiter votre propre instance auto-hébergée sur cet hôte, définissez `QUIRE_H5P_IMAGE` sur son image et démarrez le profil `h5p`. Compose la publie sur le port `QUIRE_H5P_PORT` (8090) et conserve ses données dans le volume `h5p-data` ; l’image et les obligations qui l’accompagnent restent sous votre responsabilité.

## Paramètres <!--quire:settings-->

Chaque processus lit `docker/.env`. Le modèle `docker/.env.example` répertorie chaque paramètre et sa valeur par défaut. Les groupes :

### Adresses <!--quire:addresses-->

| Paramètre | Signification |
| --- | --- |
| `QUIRE_APP_ORIGIN` | Adresse publique du LMS, par exemple `https://learn.example.com` |
| `QUIRE_CONTENT_ORIGIN` | Origine du contenu, sur un autre hôte |
| `QUIRE_PLATFORM_DOMAINS` | Domaines utilisés par les organisations, séparés par des virgules |
| `QUIRE_MARKETING_ORIGIN` | Optional. The marketing site, default `https://quirelms.com`. The only origin the waitlist form (`POST /api/waitlist`, `POST /waitlist`) accepts and redirects to. Comma separated; a `www.` variant is allowed only if listed |
| `QUIRE_DEPLOY_TARGET` | `compose` ici. Consultez les autres guides pour `vercel` et `cloudflare` |
| `QUIRE_TRUSTED_PROXY_CIDRS` | Plages des proxys dont le `X-Forwarded-For` est considéré comme fiable |

### Secrets <!--quire:secrets-->

| Paramètre | Signification |
| --- | --- |
| `QUIRE_SECRET_KEY` | Signe les sessions et les jetons. 64 caractères hexadécimaux |
| `QUIRE_MASTER_KEY` | Protège les identifiants enregistrés tels que les secrets SSO et webhook. 32 octets en base64. La couche Web et le worker doivent utiliser la même valeur. Rotation : [key-rotation.md](/fr/ops/key-rotation/) |
| `QUIRE_MASTER_KEY_VERSION` | Étiquette de version de la clé principale, `v1` si elle n’est pas définie. Incrémentez-la lors d’une rotation |
| `QUIRE_MASTER_KEY_RETIRED` | Clés principales antérieures encore nécessaires pour lire les données qu’elles ont scellées, au format `v1=<base64>`. À supprimer une fois la rotation terminée sans élément non résolu |
| `QUIRE_COLLAB_SIGNING_KEY` | Partagée par web et collab pour signer les jetons d’édition |
| `QUIRE_BACKUP_SIGNING_KEY` | Signe les sauvegardes de cours (facultatif) |

Conservez une copie de `QUIRE_MASTER_KEY` ailleurs que sur cet hôte. Sans elle, une base restaurée ne peut pas déchiffrer les identifiants qu’elle contient.

### Base de données <!--quire:database-->

| Paramètre | Signification |
| --- | --- |
| `POSTGRES_PASSWORD` | Mot de passe du superutilisateur, utilisé par le conteneur et les sauvegardes |
| `QUIRE_DB_APP_PASSWORD`, `QUIRE_DB_MIGRATOR_PASSWORD`, `QUIRE_DB_REPORT_PASSWORD`, `QUIRE_DB_AUDIT_PASSWORD` | Mots de passe des rôles, définis au premier démarrage |
| `DATABASE_URL` | Rôle applicatif. La sécurité au niveau des lignes s’applique à toutes ses requêtes |
| `DATABASE_MIGRATOR_URL`, `QUIRE_MIGRATION_URL` | Rôle du migrateur pour `migrate` et `init` |
| `QUIRE_SUPERUSER_URL` | Utilisé uniquement au premier démarrage |
| `QUIRE_REPORT_DATABASE_URL` | Rôle de rapport en lecture seule pour les rapports et leur générateur |
| `QUIRE_AUDIT_DATABASE_URL` | Rôle d’audit pour la console d’audit et l’export SIEM |
| `QUIRE_DATABASE_ID` | N’importe quel UUID, fixe pendant toute la durée de l’installation |

Les mots de passe des rôles ne sont appliqués qu’à la création initiale du volume de base de données. Pour en modifier un par la suite, utilisez `ALTER ROLE`, puis mettez à jour l’URL correspondante.

`QUIRE_REPORT_DATABASE_URL` concerne la base physique configurée dans `DATABASE_URL`. Pour toute autre base physique enregistrée, définissez sa propre URL de connexion `quire_report` dans les environnements Web et worker, puis indiquez le nom de sa variable dans le champ **Variable d’environnement de rapport** de cette base, sous la forme `env:NAME`. La référence doit pointer vers la même base que la connexion applicative, idéalement sa réplique en lecture seule. Chaque interface de rapport suit le locataire jusqu’à la connexion de rapport de sa propre base : générateur et rapports enregistrés, envois planifiés, exportations de rapports, analyses, journal d’audit, ressources d’audit REST et recherche d’audit de l’assistant. Aucune n’emprunte l’URL de rapport d’une autre base. Si une base ne dispose pas de connexion de rapport, les rapports ordinaires utilisent sa propre connexion applicative ; les analyses et toutes les lectures d’audit sont refusées avec une explication, car le rôle applicatif ne peut pas lire la piste d’audit.

### Pilotes <!--quire:drivers-->

| Paramètre | Options de cette version | Remarques |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (par défaut), `s3` ou `azure` | `local` conserve les fichiers dans le volume `files`. `s3` couvre AWS S3, R2, l’interopérabilité GCS et d’autres stockages compatibles S3, avec des téléversements multiparties reprenables |
| `QUIRE_REALTIME_DRIVER` | `inprocess` (par défaut), `sse`, `centrifugo` ou `durable_objects` | `inprocess` convient à un conteneur Web unique ; utilisez `centrifugo` ou `sse` s’il y en a plusieurs |
| `QUIRE_CACHE_DRIVER` | `memory` (par défaut), `postgres` ou `valkey` | `memory` est propre à chaque processus ; utilisez `valkey` ou `postgres` pour appliquer les limites de débit sur tous les conteneurs |
| `QUIRE_VIDEO_DRIVER` | `ffmpeg` (par défaut) ou `progressive_mp4` | Ou un fournisseur hébergé : Cloudflare Stream, Mux ou Bunny, avec leurs clés |
| `QUIRE_IMAGE_DRIVER` | `noop` (par défaut), `imgproxy` ou `cloudflare` | `noop` sert toutes les images à leur taille originale. `imgproxy` nécessite le profil `images` et les paramètres ci-dessous ; `cloudflare` utilise Cloudflare Images |
| `QUIRE_MEETING_PROVIDER` | `bbb`, `zoom`, `teams`, `meet`, `jitsi` ou `in_process` | Fournisseur par défaut de la plateforme pour les sessions en direct. Si ce paramètre n’est pas défini, les sessions indiquent qu’elles ne sont pas configurées tant qu’une organisation n’a pas connecté son propre compte dans Intégrations, Fournisseur de sessions en direct. Son compte propre prévaut toujours. Les paramètres propres aux fournisseurs (`BBB_URL` et `BBB_SECRET`, variables `ZOOM_*`, `TEAMS_*`, `GOOGLE_MEET_*` et `JITSI_*`) sont lus uniquement pour le fournisseur nommé ici |
| `QUIRE_MEETING_REGIONS` | Liste séparée par des virgules : `eu`, `uk`, `us` | Régions où le fournisseur par défaut de la plateforme traite les réunions. Si ce paramètre n’est pas défini, il n’est pas comparé à la région imposée à une organisation, comme auparavant. La page du compte propre d’une organisation indique ses régions |

Au démarrage, la couche Web refuse un pilote absent de cette version en nommant le paramètre, au lieu de le remplacer silencieusement par la valeur par défaut.

### Images <!--quire:images-->

Les pages demandent des images à quatre tailles fixes via `/api/files/{id}/image/{size}` ; ce point de terminaison vérifie les mêmes droits d’accès que pour le fichier, puis redirige vers le service d’images. Chaque organisation peut demander jusqu’à `QUIRE_IMAGE_SPECS_PER_HOUR` (2000 par défaut) nouvelles paires image/taille par heure ; les tailles déjà produites pendant cette heure ne sont pas comptées. Si vous utilisez plusieurs conteneurs Web, définissez `valkey` ou `postgres` pour `QUIRE_CACHE_DRIVER` afin que la limite soit commune.

| Paramètre | Pilote | Remarques |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | Adresse utilisée par les navigateurs pour joindre imgproxy, par exemple `https://images.example.org`. Le profil `images` le publie sur le port `QUIRE_IMAGES_PORT` (8082) |
| `IMGPROXY_KEY`, `IMGPROXY_SALT` | `imgproxy` | Chaînes hexadécimales, identiques aux valeurs de démarrage d’imgproxy. Générez chacune avec `openssl rand -hex 32`. Quire signe chaque adresse d’image avec ces valeurs ; imgproxy ne peut donc rendre que les images demandées par Quire |
| `QUIRE_IMAGE_SOURCE_ORIGIN` | `imgproxy` avec stockage local | Origine depuis laquelle imgproxy récupère les originaux. Compose définit `http://web:3000`. Avec le stockage `s3` ou `azure`, imgproxy les récupère dans le bucket ; ce paramètre est alors inutilisé |
| `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_IMAGES_TOKEN`, `CLOUDFLARE_IMAGES_ACCOUNT_HASH` | `cloudflare` | Jeton API avec autorisation de modification Images et hash du compte dans Images, Developer resources. Activez les variantes flexibles pour le compte |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | Facultatif. Si défini, les images sont privées et chaque adresse est signée et expire. Sans cette clé, les images sont publiques, à des adresses dérivées de `QUIRE_SECRET_KEY` que personne ne peut deviner |

Cloudflare Images conserve sa propre copie de chaque original qu’il sert. Lorsqu’un fichier est supprimé, le worker supprime cette copie avant l’original.

### File de travaux <!--quire:queue-->

Les travaux d’arrière-plan utilisent pg-boss dans la même base Postgres ; aucun service de file n’est à exécuter ou à configurer. Les travaux sont ajoutés à la file dans la même transaction que la modification qui les déclenche : un plantage ne peut donc ni en perdre ni en envoyer deux fois. Ici, `QUIRE_QUEUE_DRIVER` vaut `pgboss`, sa valeur par défaut ; `vercel` et `cloudflare` ne déplacent que les envois légers de notifications et de webhooks vers la file propre à la plateforme. Les guides Vercel et Cloudflare expliquent ces files et la façon dont leurs couches Web y ajoutent les travaux.

### E-mail <!--quire:email-->

Définissez l’un de ces paramètres :

- `QUIRE_EMAIL_PROVIDER_CONFIG` : objet JSON qui indique un fournisseur HTTP et ses identifiants, par exemple `{"provider":"postmark","token":"..."}`. Postmark, Amazon SES, Mailgun, SendGrid et Resend sont pris en charge.
- `QUIRE_SMTP_URL` : `smtp://user:password@host:587`. Uniquement pour cette cible ; les environnements sans serveur bloquent SMTP.

`QUIRE_MAIL_FROM` indique l’expéditeur. Pour essayer Quire, démarrez le profil `devmail`, définissez `QUIRE_SMTP_URL=smtp://mailpit:1025` et consultez les e-mails sur `http://localhost:8025`.

### Services facultatifs <!--quire:optional-services-->

| Paramètre | Profil requis |
| --- | --- |
| `CLAMAV_URL=tcp://clamav:3310` | `scan` |
| `GOTENBERG_URL=http://gotenberg:3000` | `preview` |
| `IMGPROXY_KEY`, `IMGPROXY_SALT` | `images` |
| `VALKEY_URL=redis://valkey:6379` | `cache` |
| `QUIRE_OPENSEARCH_URL` ou `QUIRE_MEILISEARCH_URL` | Recherche externe ; sinon, recherche en texte intégral Postgres |
| `QUIRE_BREACH_CHECK_PROVIDER=off`, `QUIRE_BREACH_CHECK_URL` | Vérification des fuites de mots de passe. Activée par défaut contre `api.pwnedpasswords.com` (seul le préfixe de cinq caractères du hash est envoyé) ; `off` la désactive et l’URL désigne une API de plage que vous hébergez |

### Observabilité <!--quire:observability-->

`OTEL_EXPORTER_OTLP_ENDPOINT` désigne le collecteur auquel chaque processus envoie ses traces et ses métriques ; avec le profil `observability`, sa valeur est `http://otelcol:4318`, et `docker/otel-collector.yaml` permet d’ajouter l’exportateur de votre backend. Une fois ce paramètre défini, les processus Web, worker, scheduler, content et collab exportent des spans via OTLP/HTTP (requêtes Web, transactions des bases de locataires, travaux des workers et appels sortants), ainsi que des métriques vers le même point de terminaison chaque minute (`OTEL_METRICS_EXPORTER=none` les désactive). `OTEL_TRACES_SAMPLER_ARG` définit la proportion de traces conservées. Les journaux sont envoyés sur la sortie standard au niveau `LOG_LEVEL`, et Compose les fait tourner. Les traces ne contiennent aucune donnée personnelle.

### Sortie réseau régionale (résidence des données dans l’UE) <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` indique que la pile sert des organisations de l’Union européenne. Le worker limite alors à une liste d’autorisation toute requête sortante effectuée pour une organisation dont la région est l’UE (21-compliance.md, section 8.1). Cette liste comprend les hôtes déclarés pour la région par les services configurés (point de terminaison de stockage, fournisseur de messagerie, fournisseur vidéo hébergé, destinations de stockage propres à l’organisation, fournisseurs d’IA et compte de messagerie), les hôtes des services faisant l’objet d’une dérogation active et ceux indiqués dans `QUIRE_EGRESS_ALLOW_HOSTS`. Toute requête vers un autre hôte public est refusée avant son envoi ; le refus est inscrit dans la piste d’audit de l’organisation sous `privacy/egress_refused`, et figure sous Conformité, Résidence des données.

| Paramètre | Valeurs | Effet |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | Liste de noms d’hôtes séparés par des virgules ou `*.example.org` pour inclure tous les sous-domaines | Hôtes supplémentaires qu’une organisation de l’UE peut joindre. Les points de terminaison webhook, xAPI et SIEM, les flux de blog et les hôtes Amazon SES doivent y figurer, car ils relèvent du choix de l’organisation et ne sont déclarés par aucun service. Les adresses loopback, les adresses privées et les noms à étiquette unique comme `web` ou `clamav` appartiennent à votre réseau et ne sont jamais vérifiés |

Les organisations du Royaume-Uni et des États-Unis ne sont pas limitées à une liste d’hôtes ; elles conservent les contrôles de région des services. Définissez la liste sur le worker ; la page d’administration la lit sur la couche Web pour afficher la liste d’autorisation. Placez-la donc dans `docker/.env`, lu par tous les services.

Le contrôle applicatif fournit une erreur claire et une entrée d’audit, mais ce n’est pas la garantie : le code peut contenir une erreur. La garantie repose sur le réseau. Compose ne l’applique pas à votre place. Pour une pile régionale, placez les services `worker` et `web` sur un réseau `internal: true` dont la seule sortie passe par un proxy egress (par exemple un conteneur Squid ou tinyproxy) autorisant les mêmes hôtes que `QUIRE_EGRESS_ALLOW_HOSTS`, ainsi que ceux des services configurés, et définissez `HTTPS_PROXY` pour ces services. La page de résidence répertorie précisément les hôtes autorisés par l’application afin de comparer les deux listes.

## Santé <!--quire:health-->

| Point de terminaison | Signification |
| --- | --- |
| `/healthz` | Disponibilité : le processus répond. Compose l’utilise pour les contrôles de santé |
| `/readyz` | État prêt : les dépendances sont accessibles et chaque service facultatif est signalé comme configuré ou non. Pointez votre répartiteur de charge ici |

`docker compose -f docker/compose.yaml ps` affiche l’état de santé de chaque service.

## TLS <!--quire:tls-->

Le service `proxy` (Caddy, Apache-2.0, `docker/caddy/Caddyfile`) appartient à la pile par défaut. Il répond sur les ports 80 et 443 et redirige :

| Hôte ou chemin | Destination |
| --- | --- |
| `QUIRE_PROXY_CONTENT_HOST` | `content` |
| `QUIRE_PROXY_APP_HOST`, tous les sous-domaines de locataires et domaines personnalisés | `web` |
| `/_collab/` sur ces hôtes | `collab` (WebSocket, `QUIRE_COLLAB_URL`) |
| `/_realtime/connection/` sur ces hôtes | WebSocket client de `centrifugo` ; son API serveur n’est jamais exposée |
| `/_images/` sur ces hôtes | `imgproxy`, avec le profil `images` (`IMGPROXY_URL`) |

`init-env.sh` déduit `QUIRE_PROXY_APP_HOST`, `QUIRE_PROXY_CONTENT_HOST`, `QUIRE_PROXY_HTTPS_PORT`, `QUIRE_COLLAB_URL` et `IMGPROXY_URL` des deux origines, afin qu’ils restent cohérents. Si vous modifiez une origine manuellement, modifiez-les ensemble.

Les certificats dépendent de `QUIRE_PROXY_TLS` :

- `internal` (valeur par défaut) : l’autorité de certification propre à Caddy, pour `localhost`, `*.localhost` et `lvh.me`. Faites confiance une fois à son certificat racine, puis ouvrez :

  ```sh
  docker compose -f docker/compose.yaml cp \
    proxy:/data/caddy/pki/authorities/local/root.crt ./quire-local-ca.crt
  ```

  Ajoutez `quire-local-ca.crt` au magasin de confiance du système ou du navigateur. Pour `curl`, indiquez-le avec `--cacert`.
- Une adresse e-mail : certificats ACME automatiques (Let's Encrypt, puis ZeroSSL) pour les noms d’hôte réels. Le DNS des deux origines et de chaque hôte de locataire doit pointer ici ; les ports 80 et 443 doivent être accessibles depuis Internet.

Les certificats des hôtes de locataires sont émis à la demande, lors de la première visite uniquement, et seulement lorsque Web confirme que le nom appartient à cette installation (`/tls-allowed`, interrogé sur le réseau Compose). Aucun certificat générique ni plug-in de fournisseur DNS n’est nécessaire ; une personne inconnue qui pointe un nom vers l’hôte ne peut pas provoquer l’émission d’un certificat. Les certificats et l’autorité locale résident dans le volume `caddy-data` ; sauvegardez-le avec le reste si vous utilisez `internal`.

Web ne fait confiance à `X-Forwarded-For` que lorsqu’il provient du proxy : celui-ci a une adresse fixe (`QUIRE_PROXY_ADDRESS`, `172.29.64.10` par défaut) sur un sous-réseau fixe (`QUIRE_COMPOSE_SUBNET`), et `QUIRE_TRUSTED_PROXY_CIDRS` désigne cette adresse. Si le sous-réseau entre en conflit avec un réseau de l’hôte, modifiez les deux paramètres et exécutez `docker compose down` avant `up`.

## Derrière votre propre proxy inverse <!--quire:behind-your-own-reverse-proxy-->

Pour utiliser à la place un répartiteur de charge ou un proxy déjà en service, ne démarrez pas `proxy` (`docker compose up -d --scale proxy=0`) et terminez TLS devant `web` (8080), `content` (8081), `collab` (1234, WebSocket) et `centrifugo` (8000, WebSocket). Définissez les adresses publiques dans `QUIRE_APP_ORIGIN`, `QUIRE_CONTENT_ORIGIN` et `QUIRE_COLLAB_URL` (`wss://`), et la plage d’adresses de votre proxy dans `QUIRE_TRUSTED_PROXY_CIDRS`.

## Dépannage <!--quire:troubleshooting-->

- `init` se termine avec « QUIRE_DATABASE_ID is not a UUID » : définissez la valeur avec `uuidgen`.
- `web` redémarre avec « did not start on compose » : le journal répertorie les paramètres qu’il ne peut pas accepter et les valeurs à utiliser à la place.
- Modifier un mot de passe de rôle dans `.env` après le premier démarrage n’a aucun effet : le script d’initialisation ne s’exécute qu’une fois. Utilisez `ALTER ROLE`.
- Les téléversements échouent avec une erreur d’analyse alors que `CLAMAV_URL` est défini : ClamAV télécharge ses signatures au premier démarrage, ce qui prend quelques minutes.

Source: https://docs.quirelms.com/fr/ops/install/index.mdx
