diff --git a/README.md b/README.md index 4c99bdc..08825fb 100644 --- a/README.md +++ b/README.md @@ -455,16 +455,30 @@ elle aucun projet ne peut être créé faute de langue source à choisir. ### Déployer via Coolify -1. **Nouvelle ressource → Docker Compose**, dépôt +> **Le build pack doit être « Docker Compose ».** C'est le réglage qui décide de +> tout le reste, et Coolify ne le devine pas correctement : à la création d'une +> ressource il détecte « application PHP » et choisit **Nixpacks**, qui ignore le +> Dockerfile comme le compose, installe PHP 8.3 et lance +> `composer install --ignore-platform-reqs` — dépendances de développement +> comprises. Le build échoue alors sur +> `Lazy loading proxies require PHP 8.4 or higher`, une erreur qui ne dit rien du +> vrai problème : ce n'est pas le bon constructeur qui tourne. + +1. **Nouvelle ressource → Docker Compose** (surtout pas *Nixpacks*), dépôt `ssh://git@git.tranquilys.com:22222/Stephan/TQ-Slator.git`, branche `main`. + Sur une ressource existante : *Configuration → General → Build Pack*. 2. Fichier compose : `compose.prod.yaml`. Ne pas laisser `compose.yaml`, que - Coolify propose par défaut. + 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. 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 TLS est terminé par le proxy de Coolify ; Caddy a donc `auto_https off`, et `SYMFONY_TRUSTED_PROXIES` est renseigné pour que Symfony lise `X-Forwarded-Proto` — sans quoi les liens d'invitation partiraient en `http://` diff --git a/compose.prod.yaml b/compose.prod.yaml index 88e1c55..9d28ee9 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -45,17 +45,20 @@ services: # concerne que la Delivery API appelée depuis un autre domaine. CORS_ALLOW_ORIGIN: '${CORS_ALLOW_ORIGIN:-^$$}' - # `?` : absente, la variable arrête le déploiement au lieu de laisser - # démarrer un service à moitié configuré. - APP_SECRET: '${APP_SECRET:?openssl rand -hex 32}' - DATABASE_URL: 'mysql://tqslator:${MARIADB_PASSWORD:?mot de passe MariaDB}@database:3306/tqslator?serverVersion=11.4.0-MariaDB&charset=utf8mb4' + # Interpolation simple, sans la forme `${VAR:?message}` : celle-ci arrête + # bien `docker compose` sur une variable manquante, mais le parseur de + # Coolify ne la comprend pas partout. Le refus est donc porté par + # docker/entrypoint.prod.sh, où il est testé — et où le message explique + # quoi faire plutôt que de lister un nom de variable. + APP_SECRET: '${APP_SECRET}' + DATABASE_URL: 'mysql://tqslator:${MARIADB_PASSWORD}@database:3306/tqslator?serverVersion=11.4.0-MariaDB&charset=utf8mb4' REDIS_URL: 'redis://cache:6379' # Sert à composer les liens d'invitation envoyés par e-mail. Une valeur # fausse ne casse rien de visible ici : elle casse la réception, ailleurs, # plus tard. L'entrypoint refuse donc localhost. - BACK_OFFICE_URL: '${BACK_OFFICE_URL:?URL publique du back-office}' - MAILER_DSN: '${MAILER_DSN:?DSN SMTP réel, Mailpit ne part pas en production}' + BACK_OFFICE_URL: '${BACK_OFFICE_URL}' + MAILER_DSN: '${MAILER_DSN}' MAILER_FROM: '${MAILER_FROM:-no-reply@tranquilys.com}' DEFAULT_ORGANIZATION_SLUG: '${DEFAULT_ORGANIZATION_SLUG:-tranquilys}' @@ -83,11 +86,11 @@ services: environment: APP_ENV: prod APP_DEBUG: '0' - APP_SECRET: '${APP_SECRET:?openssl rand -hex 32}' - DATABASE_URL: 'mysql://tqslator:${MARIADB_PASSWORD:?mot de passe MariaDB}@database:3306/tqslator?serverVersion=11.4.0-MariaDB&charset=utf8mb4' + APP_SECRET: '${APP_SECRET}' + DATABASE_URL: 'mysql://tqslator:${MARIADB_PASSWORD}@database:3306/tqslator?serverVersion=11.4.0-MariaDB&charset=utf8mb4' REDIS_URL: 'redis://cache:6379' - BACK_OFFICE_URL: '${BACK_OFFICE_URL:?URL publique du back-office}' - MAILER_DSN: '${MAILER_DSN:?DSN SMTP réel}' + BACK_OFFICE_URL: '${BACK_OFFICE_URL}' + MAILER_DSN: '${MAILER_DSN}' MAILER_FROM: '${MAILER_FROM:-no-reply@tranquilys.com}' DEFAULT_ORGANIZATION_SLUG: '${DEFAULT_ORGANIZATION_SLUG:-tranquilys}' # Ne migre pas : il ATTEND que le schéma soit à jour. @@ -119,8 +122,8 @@ services: environment: MARIADB_DATABASE: tqslator MARIADB_USER: tqslator - MARIADB_PASSWORD: '${MARIADB_PASSWORD:?mot de passe MariaDB}' - MARIADB_ROOT_PASSWORD: '${MARIADB_ROOT_PASSWORD:?mot de passe root MariaDB}' + MARIADB_PASSWORD: '${MARIADB_PASSWORD}' + MARIADB_ROOT_PASSWORD: '${MARIADB_ROOT_PASSWORD}' command: # Doit correspondre à default_table_options de doctrine.yaml, sinon les # tables créées hors migration divergent en silence. Voir §3.6 de diff --git a/composer.json b/composer.json index 87e1247..6446d14 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "minimum-stability": "stable", "prefer-stable": true, "require": { - "php": ">=8.3", + "php": ">=8.4", "ext-ctype": "*", "ext-iconv": "*", "ext-intl": "*", diff --git a/composer.lock b/composer.lock index eb525e1..828fe3c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cdd141b5f1000a8c6bde9febd6fba449", + "content-hash": "5b8da7895e6fa84a780b9b1972339e4e", "packages": [ { "name": "api-platform/doctrine-common", @@ -11925,7 +11925,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=8.3", + "php": ">=8.4", "ext-ctype": "*", "ext-iconv": "*", "ext-intl": "*", @@ -11937,5 +11937,5 @@ "platform-overrides": { "php": "8.4.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/docker/entrypoint.prod.sh b/docker/entrypoint.prod.sh index c24817f..74d41aa 100755 --- a/docker/entrypoint.prod.sh +++ b/docker/entrypoint.prod.sh @@ -28,6 +28,19 @@ if [ -z "${DATABASE_URL:-}" ]; then exit 1 fi +# Le DSN est composé dans compose.prod.yaml à partir de MARIADB_PASSWORD. +# Oubliée, la variable produit « mysql://tqslator:@database:… » — un DSN +# syntaxiquement valide, avec un mot de passe vide. MariaDB refuse alors la +# connexion, et le message qui remonte parle de droits d'accès, jamais de la +# variable manquante. +case "$DATABASE_URL" in + *://*:@*) + echo '[entrypoint] Le mot de passe de la base est vide dans DATABASE_URL.' >&2 + echo '[entrypoint] Renseignez MARIADB_PASSWORD.' >&2 + exit 1 + ;; +esac + # BACK_OFFICE_URL sert à composer les liens d'invitation. Laissé sur sa valeur # de développement, il enverrait des e-mails pointant vers localhost — une # panne qui ne se voit que du côté du destinataire, plusieurs jours plus tard.