Déployer avec Docker Compose
This content is not available in your language yet.
Le fichier infra/compose/docker-compose.yml est le Compose officiel de
Cenaclo : proxy-agnostique, il sert aussi bien derrière Coolify que lancé
directement par un opérateur. Ce parcours s’adresse à celles et ceux qui
veulent piloter Docker eux-mêmes, brancher leur propre reverse proxy ou
intégrer le déploiement dans une chaîne d’intégration continue existante.
Si vous cherchez le chemin le plus court vers une instance en HTTPS, préférez le parcours Coolify.
Prérequis
Section intitulée « Prérequis »- Un hôte Docker Linux avec Docker Engine et le plugin Compose v2. Voir Dimensionner le serveur.
- Un checkout du dépôt Cenaclo sur l’hôte de déploiement. Contrairement au
template Coolify, qui tire des images publiées, ce Compose construit les
services
backendetwebdepuis les sources du dépôt. Le checkout est donc la référence de version de votre installation. - Un domaine public pointant vers l’hôte si vous voulez le TLS intégré
(profil
caddy).
1. Préparer l’environnement
Section intitulée « 1. Préparer l’environnement »cp infra/compose/.env.example infra/compose/.envRenseignez ensuite les valeurs réelles dans infra/compose/.env. Ce fichier
contient des secrets : il n’est pas versionné et ne doit jamais l’être.
Les variables les plus structurantes :
| Variable | Rôle |
|---|---|
APP_BASE_URL, CORS_ORIGINS |
URL publique de l’application, utilisée pour les liens et l’origine autorisée |
POSTGRES_PASSWORD, DATABASE_URL |
Accès Postgres ; les deux doivent rester cohérents |
JWT_PRIVATE_KEY, JWT_PUBLIC_KEY, AUTH_IP_SALT, EMAIL_HASH_PEPPER |
Secrets applicatifs, à générer une fois pour toutes |
CENACLO_MASTER_KEY_SECRET |
Matériel de la master key du chiffrement au repos |
INSTALL_KEYS_HOST_DIR |
Répertoire hôte des clés d’installation, /etc/cenaclo/keys par défaut |
S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET |
Accès au stockage objet SeaweedFS embarqué |
LIVEKIT_API_KEY, LIVEKIT_API_SECRET |
Identifiants LiveKit ; le secret doit faire au moins 32 caractères |
LISTMONK_DB_PASSWORD, LISTMONK_ADMIN_PASSWORD |
Listmonk embarqué |
VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT |
Clés Web Push ; le backend refuse de démarrer sans elles |
Les secrets d’authentification et la master key se produisent en une fois :
bash scripts/gen-keys.shCe script produit exactement JWT_PRIVATE_KEY, JWT_PUBLIC_KEY,
JWT_ACTIVE_KID, AUTH_IP_SALT et CENACLO_MASTER_KEY_SECRET. Il ne produit ni
EMAIL_HASH_PEPPER ni les clés Web Push. Le pepper est accepté dès seize
caractères : laissé à la valeur d’exemple du fichier, il passe la validation au
démarrage, sans aucun message, et rend les empreintes d’email prévisibles.
Générez-le donc explicitement :
printf 'EMAIL_HASH_PEPPER=%s\n' "$(openssl rand -base64 32)"Les clés Web Push ont leur propre commande de génération, indiquée en
commentaire juste au-dessus des variables VAPID_* dans
infra/compose/.env.example. Elle imprime les trois lignes au format .env ;
reportez ensuite la clé publique dans VITE_VAPID_PUBLIC_KEY, l’argument de
build de la SPA, sinon l’abonnement aux notifications échoue côté navigateur.
Sur le parcours Coolify, ces secrets sont générés au premier démarrage et vous n’avez rien à produire à la main.
Le service one-shot install-keys-init prépare INSTALL_KEYS_HOST_DIR sur
l’hôte : il en fixe le propriétaire et le mode 0700. C’est dans ce répertoire
que le wizard d’installation écrit la clé master.age. Le montage doit rester
accessible en écriture au conteneur backend.
2. Démarrer la stack
Section intitulée « 2. Démarrer la stack »docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml up -dServices permanents : postgres (Postgres 18), redis (Redis 7), seaweedfs,
livekit, livekit-egress, listmonk, backend et web. Quatre exécutions
ponctuelles complètent l’amorçage puis sortent en code 0 : install-keys-init
décrit ci-dessus, listmonk-db-init, listmonk-seed et
livekit-egress-config. Une stack saine affiche donc huit conteneurs en cours
d’exécution et quatre terminés dans docker compose ps --all.
Le backend applique ses migrations de schéma pendant son démarrage. Aucune commande de migration séparée n’est à lancer.
3. Choisir son exposition publique
Section intitulée « 3. Choisir son exposition publique »Par défaut, le Compose ne publie aucun port sur l’hôte. Les services
web et backend restent joignables uniquement depuis le réseau Docker
interne, nommé par INTERNAL_NETWORK_NAME (salon-internal par défaut). Cette
neutralité est volontaire : elle permet de placer le proxy de votre choix
devant la stack. Trois options.
Option A — Profil caddy intégré
Section intitulée « Option A — Profil caddy intégré »docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml --profile caddy up -dCe profil ajoute Caddy, qui publie ${CADDY_HTTP_PORT:-80} et
${CADDY_HTTPS_PORT:-443} sur l’hôte et obtient un certificat Let’s Encrypt
pour CADDY_DOMAIN. Le domaine doit être public et pointer vers l’hôte : sans
cela, la validation Let’s Encrypt échoue.
Le Caddyfile fourni sert un seul domaine pour toute l’application : il
route les WebSockets (/ws/*, /socket.io/*) et les routes d’API vers
backend:3000, avec ou sans préfixe /api, et tout le reste vers web:80.
Aucune variable supplémentaire n’est nécessaire côté SPA dans cette
configuration. Alignez simplement APP_BASE_URL et CORS_ORIGINS sur
https://<CADDY_DOMAIN>.
Option B — Reverse proxy tiers
Section intitulée « Option B — Reverse proxy tiers »Si vous utilisez déjà Nginx, Traefik ou un autre proxy, ne lancez pas le profil
caddy. Deux branchements sont possibles :
- Proxy conteneurisé : connectez-le au réseau
${INTERNAL_NETWORK_NAME:-salon-internal}et proxifiez versweb:80etbackend:3000. - Proxy installé sur l’hôte : ajoutez un fichier de surcharge Compose qui
publie les ports voulus sur
127.0.0.1, puis pointez le proxy dessus.
Si votre proxy expose l’API sur un domaine distinct de la SPA, la SPA doit
connaître cette URL. Le seul levier câblé par le fichier livré est l’argument de
build VITE_API_BASE_URL : renseignez-le dans infra/compose/.env, puis
reconstruisez l’image web. L’image sait aussi lire CENACLO_API_BASE_URL au
démarrage du conteneur, mais le fichier livré ne déclare pas cette clé dans
l’environment: du service web : posée seule dans infra/compose/.env, elle
n’atteint jamais le conteneur et la SPA retombe silencieusement sur sa propre
origine, sans message d’erreur. Pour l’utiliser sans reconstruire l’image,
ajoutez un fichier de surcharge qui déclare la clé sur le service web. Dans
les deux cas, la valeur doit commencer par http:// ou https://, ou valoir
exactement /api pour un montage sous-chemin sur le même domaine.
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml up -d --build webDans tous les cas, les en-têtes HTTP de sécurité sont portés par le backend Fastify, pas par le proxy. Ils sont donc présents même sans Caddy et même sans Coolify ; un proxy qui les réécrirait dégraderait la configuration au lieu de l’améliorer.
Option C — Aucune exposition publique
Section intitulée « Option C — Aucune exposition publique »Utile pour un environnement de préproduction interne. La stack reste alors
accessible uniquement depuis le réseau Docker, ce qui suffit pour les
vérifications par docker compose exec décrites plus bas.
4. Terminer le wizard d’installation
Section intitulée « 4. Terminer le wizard d’installation »Ouvrez https://<votre-domaine>/install et suivez les six étapes : domaine,
compte administrateur, passphrase de chiffrement, double authentification TOTP,
communauté, branding.
En mode Compose standalone, la clé d’installation vit hors du fichier .env,
dans INSTALL_KEYS_HOST_DIR (/etc/cenaclo/keys), avec des permissions
restreintes posées par install-keys-init.

Capture prise à la fin d’un parcours Compose réel : une fois le wizard terminé, le backoffice s’ouvre sur la checklist de démarrage, qui liste les jalons restants avant d’inviter les premiers membres.
5. Profils optionnels
Section intitulée « 5. Profils optionnels »Profil coturn — live entièrement auto-hébergé
Section intitulée « Profil coturn — live entièrement auto-hébergé »docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml --profile coturn up -dCe profil exige TURN_STATIC_AUTH_SECRET d’au moins 32 caractères ; le service
refuse de démarrer sinon. Il utilise le réseau de l’hôte et une large plage
UDP : il s’adresse aux opérateurs capables d’administrer le firewall. Les ports
à ouvrir sont listés dans Firewall self-hosting.
Le relay TURN mutualisé reste le chemin recommandé par défaut.
Variables associées : TURN_REALM, TURN_SERVER_NAME, TURN_EXTERNAL_IP.
Profil monitoring — GlitchTip
Section intitulée « Profil monitoring — GlitchTip »docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml --profile monitoring up -dCe profil ajoute GlitchTip et ses jobs d’amorçage sur le même Postgres, via les
variables GLITCHTIP_*. Il est facultatif et n’est pas requis par
l’application.
6. Rendre LiveKit joignable depuis les navigateurs
Section intitulée « 6. Rendre LiveKit joignable depuis les navigateurs »Le serveur LiveKit embarqué est câblé pour l’usage interne : le conteneur
livekit-egress le rejoint par ws://livekit:7880 et produit les replays sans
aucun réglage. En revanche, le Compose ne publie pas les ports média LiveKit
sur l’hôte, et LIVEKIT_PUBLIC_URL est vide par défaut, ce qui fait retomber
le backend sur l’URL interne LIVEKIT_URL.
Conséquence à connaître avant d’annoncer le live à vos membres : tant que vous n’avez pas exposé LiveKit publiquement, un navigateur ne peut pas s’y connecter. Pour un live auto-hébergé en Compose, il faut donc :
- publier les ports de signalisation et de média LiveKit vers l’extérieur, via votre proxy pour le WebSocket et via une surcharge Compose pour les ports RTC ;
- renseigner
LIVEKIT_PUBLIC_URLavec l’URLwss://publique, que le backend remet aux clients ; - ouvrir les ports correspondants sur le firewall.
Le parcours Coolify fait ce câblage pour vous en
assignant un domaine au service livekit.
Si vous branchez un serveur LiveKit externe, alignez
CENACLO_LIVE_EGRESS_ALLOWED_HOSTS sur l’hôte réellement joint par le
conteneur Egress. Une liste qui ne contient pas cet hôte fait refuser la page
de composition, donc aucun replay n’est produit.
7. Valider l’installation
Section intitulée « 7. Valider l’installation »docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml configdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml psdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec backend wget -q -O - http://127.0.0.1:3000/healthzdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec livekit-egress wget -q -O - http://127.0.0.1:7981/La sonde du backend passe par docker compose exec parce que le Compose
standalone ne publie pas le port 3000 sur l’hôte.
Les scripts d’exploitation embarqués dans l’image backend répondent tous à
--help, ce qui permet de vérifier qu’ils sont présents et exécutables :
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend /usr/local/bin/cenaclo-backup.sh --helpdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend /usr/local/bin/cenaclo-restore.sh --helpdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend /usr/local/bin/cenaclo-purge.sh --helpdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend /usr/local/bin/cenaclo-export-user.sh --help8. Exploitation courante
Section intitulée « 8. Exploitation courante »Sauvegarde quotidienne, à planifier par cron sur l’hôte :
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend \ /usr/local/bin/cenaclo-backup.sh --output-dir /var/backups/cenacloAvant d’automatiser, renseignez une source de passphrase non interactive :
CENACLO_BACKUP_PASSPHRASE_FILE pointant vers un fichier hors dépôt en mode
0600, ou à défaut CENACLO_BACKUP_PASSPHRASE dans infra/compose/.env.
Détail des stratégies dans
Sauvegardes self-hosting et
Restaurer une instance.
Purge de rétention quotidienne :
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend \ /usr/local/bin/cenaclo-purge.sh --directExport RGPD d’un utilisateur :
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec -T backend \ /usr/local/bin/cenaclo-export-user.sh --direct --user-email [email protected] --output /tmp/export.zip9. Mettre à jour
Section intitulée « 9. Mettre à jour »Le wrapper infra/ops/cenaclo-update.sh enchaîne le pull des images, la
reconstruction des services construits depuis les sources, le redémarrage puis
l’attente de la sonde /healthz :
bash infra/ops/cenaclo-update.sh \ --compose-file infra/compose/docker-compose.yml \ --env-file infra/compose/.envLe wrapper ne fait aucun retour arrière automatique. Si la sonde de santé expire, il sort en erreur et laisse la stack en l’état. Pour revenir en arrière, replacez le checkout sur la version saine connue et relancez le wrapper. Le parcours détaillé, ainsi que le cas d’une migration destructive, sont décrits dans Mettre à jour.
En cas de problème, la page Dépannage recense les pannes les plus fréquentes.