diff --git a/README.md b/README.md index 08825fb..240ad5c 100644 --- a/README.md +++ b/README.md @@ -470,14 +470,39 @@ elle aucun projet ne peut être créé faute de langue source à choisir. 2. Fichier compose : `compose.prod.yaml`. Ne pas laisser `compose.yaml`, que Coolify propose par défaut — Docker y fusionnerait `compose.override.yaml`. 3. Renseigner les variables du tableau ci-dessus dans l'onglet *Environment*. -4. Attribuer le domaine au service **`php`**. `SERVICE_FQDN_PHP_80` est déjà - déclaré dans le fichier : Coolify y place le domaine et configure son proxy. +4. Poser le domaine **sur le service `php`**, et sur lui seul. Avec le build + pack Docker Compose, Coolify liste chaque service et attend le domaine sur + celui qui répond en HTTP — pas au niveau de la ressource. Un domaine posé + ailleurs laisse `php` sans route, et le proxy répond **403** à un domaine + qu'il ne connaît pas. 5. Déployer, puis lancer la commande d'amorçage ci-dessus depuis le terminal de la ressource. -Le domaine attribué par défaut est en `http://…sslip.io`. Il fonctionne, mais -les liens d'invitation partiront en clair : posez un vrai domaine en HTTPS avant -d'inviter qui que ce soit. +Le fichier ne déclare **pas** `SERVICE_FQDN_PHP_80`. Cette variable magique +demande à Coolify de générer un domaine en `…sslip.io` : pratique pour un modèle +en un clic, mais elle entre en concurrence avec un domaine renseigné à la main, +et l'on se retrouve avec deux routes pour un même service dont une seule +correspond au DNS réel. + +### Diagnostiquer un 403 + +Un 403 sur le domaine vient presque toujours du **proxy**, pas de +l'application : celle-ci ne renvoie jamais 403 sur `/`, elle sert le +back-office. Trois vérifications, dans cet ordre : + +```bash +# 1. La pile tourne-t-elle vraiment ? Les quatre services doivent être « running ». +docker ps --filter name=php --filter name=worker --filter name=database + +# 2. L'application répond-elle DANS le réseau, proxy contourné ? +docker exec curl -sS -o /dev/null -w '%{http_code}\n' http://localhost/api/v1/health + +# 3. Le proxy connaît-il le domaine ? +docker exec coolify-proxy cat /traefik/dynamic/*.yaml | grep -i tqslator +``` + +Si 2 répond `200` et que 3 ne trouve rien, le problème est le routage : le +domaine n'est pas posé sur le service `php`. Le TLS est terminé par le proxy de Coolify ; Caddy a donc `auto_https off`, et `SYMFONY_TRUSTED_PROXIES` est renseigné pour que Symfony lise diff --git a/compose.prod.yaml b/compose.prod.yaml index 9d28ee9..ee83972 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -19,11 +19,26 @@ services: build: context: . target: app_prod + # Le port que le proxy doit atteindre. L'image l'expose déjà, mais le + # déclarer ici lève toute ambiguïté : elle expose aussi 443 et 2019 + # (l'endpoint d'administration de Caddy), et rien n'oblige un proxy à + # deviner lequel des trois sert l'application. + # + # `expose` et non `ports` : aucune publication sur l'hôte. Le proxy atteint + # le conteneur par le réseau interne, et publier 8080 en plus exposerait + # l'application en clair à côté du HTTPS. + expose: + - '80' environment: - # Coolify remplace cette variable par le domaine attribué au service et - # configure son proxy en conséquence. Sur une VM sans Coolify, retirez - # cette ligne et ajoutez `ports: ['80:80']`. - SERVICE_FQDN_PHP_80: '/' + # PAS de `SERVICE_FQDN_PHP_80` ici, et c'est délibéré. + # + # Cette variable magique demande à Coolify de GÉNÉRER un domaine (du type + # xxxx.sslip.io) et d'y router le service. Elle rend donc service à un + # modèle en un clic, mais elle entre en concurrence avec un domaine + # renseigné à la main : on se retrouve avec deux routes pour un même + # service, dont une seule correspond au DNS réel. + # + # Le domaine se pose donc dans l'interface, sur le service `php`. SERVER_NAME: ':80' APP_ENV: prod