Aller au contenu principal

Son projet PHP dans Coolify

Démarche à suivre dans l'ordre, pour héberger un projet PHP sans framework (fichiers .php écrits à la main, éventuellement avec Composer et une base de données MySQL/MariaDB) dans Coolify.

Pour un projet Symfony, voir plutôt le tutoriel Son projet Symfony dans Coolify.

  • Étapes à suivre par l'étudiant :

    • A) Adapter le projet PHP
    • B) Pousser les modifications sur GitHub
    • MAJ du projet par l'étudiant
  • Étapes à suivre par l'enseignant :

    • C) Créer la ressource dans Coolify
    • D) Déployer
    • MAJ du projet par l'enseignant
Principe

Le projet est placé dans un conteneur Docker qui contient PHP et le serveur Web Apache. La base de données MariaDB est un second conteneur. Les informations de connexion à la base (serveur, nom, utilisateur, mot de passe) ne sont plus écrites dans le code : elles sont fournies par Coolify sous forme de variables d'environnement, que le code PHP doit lire.


A) Adapter le projet PHP​

1. Lire la configuration dans les variables d'environnement​

En production, le fichier .env n'existe pas (il est ignoré par Git, voir Utilisation d'un fichier .env) : c'est Coolify qui fournit les variables. Le code de connexion à la base doit donc fonctionner dans les deux cas.

Exemple de fichier config.php (à adapter au projet) :

<?php
require __DIR__ . '/vendor/autoload.php';

// En local : charge le fichier .env s'il existe. En production (Coolify) : ne fait rien.
Dotenv\Dotenv::createImmutable(__DIR__)->safeLoad();

// Lit une variable d'environnement (fichier .env en local, Coolify en production)
function env(string $name, ?string $default = null): ?string
{
$value = $_ENV[$name] ?? getenv($name);
return $value === false ? $default : $value;
}

$pdo = new PDO(
sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', env('DB_HOST', 'localhost'), env('DB_NAME')),
env('DB_USER'),
env('DB_PASSWORD'),
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);

Et le fichier .env local (non committé) :

DB_HOST=localhost
DB_NAME=portfolio
DB_USER=root
DB_PASSWORD=

Explications :

  • safeLoad() remplace load() : load() provoque une erreur si le fichier .env est absent, ce qui serait le cas en production.
  • getenv() lit les variables fournies par Coolify. La lecture dans $_ENV seule ne suffit pas, car en production $_ENV est vide (voir le Dockerfile, étape 2).
  • Ne plus écrire de mot de passe, ni de nom de serveur de base de données (localhost), directement dans le code : en production, le serveur de base de données s'appelle database, et le mot de passe est secret.
  • Si le projet n'utilise pas Composer ni phpdotenv, supprimer les deux premières instructions et lire uniquement getenv('DB_HOST'), etc.
  • Si le projet n'a pas de base de données, passer cette étape et supprimer le service database dans l'étape 4.

2. Dockerfile​

Créer un fichier Dockerfile à la racine du projet, avec ce contenu :

# Étape 1 : installer les dépendances Composer
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction --no-scripts

# Étape 2 : PHP + Apache
FROM php:8.4-apache

RUN docker-php-ext-install pdo_mysql mysqli \
&& mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

COPY . /var/www/html/
COPY --from=vendor /app/vendor /var/www/html/vendor

Explications :

  • Image de base officielle php:8.4-apache : Apache écoute en HTTP sur le port 80 (le HTTPS est géré par Traefik, le proxy de Coolify). Les fichiers du projet sont copiés dans /var/www/html/, le dossier servi par Apache.
  • docker-php-ext-install pdo_mysql mysqli ajoute les extensions PHP pour accéder à MariaDB (pdo_mysql pour PDO, mysqli si le projet l'utilise).
  • php.ini-production est le fichier de configuration recommandé pour la production : il masque les erreurs PHP aux visiteurs (elles restent visibles dans les logs de Coolify). Il vide aussi $_ENV, d'où l'usage de getenv() à l'étape 1.
  • La première étape installe les bibliothèques (dossier vendor/) avec Composer, sans les paquets de développement. Les fichiers composer.json et composer.lock doivent être committés.
  • Si le projet n'utilise pas Composer : supprimer l'étape 1 (les 4 premières lignes) et la ligne COPY --from=vendor ....
  • Le fichier .htaccess n'est pas pris en compte par défaut dans cette image. Un projet qui en dépend (réécriture d'URL) nécessite une configuration Apache supplémentaire : en parler à l'enseignant.

3. .dockerignore​

Créer un fichier nommé exactement .dockerignore à la racine du projet (à côté du Dockerfile), avec ce contenu :

.git/
.idea/
.vscode/
vendor/
node_modules/
.env
Dockerfile
compose.yaml
.dockerignore
database.sql

Explications :

  • Ces fichiers ne sont pas copiés dans l'image par le COPY . /var/www/html/ du Dockerfile.
  • C'est une question de sécurité : tout ce qui est copié dans /var/www/html/ est téléchargeable par n'importe quel visiteur. Sans cette liste, https://votre-site/.env ou https://votre-site/database.sql seraient accessibles.
  • vendor/ est exclu car il est reconstruit par Composer à l'étape 1 du Dockerfile.

4. compose.yaml​

Créer un fichier compose.yaml à la racine du projet, avec ce contenu :

services:
web:
build: .
restart: unless-stopped
environment:
DB_HOST: database
DB_NAME: ${MARIADB_DATABASE:-app}
DB_USER: ${MARIADB_USER:-app}
DB_PASSWORD: ${MARIADB_PASSWORD}
depends_on:
database:
condition: service_healthy

database:
image: mariadb:${MARIADB_VERSION:-11.4}
restart: unless-stopped
environment:
MARIADB_DATABASE: ${MARIADB_DATABASE:-app}
MARIADB_USER: ${MARIADB_USER:-app}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
timeout: 5s
retries: 5
start_period: 60s
volumes:
- database_data:/var/lib/mysql:rw
- ./database.sql:/docker-entrypoint-initdb.d/01-database.sql:ro

volumes:
database_data:

Explications :

  • build: . : l'image du service web est construite à partir du Dockerfile situé à la racine du projet.
  • Aucun ports: n'est publié : Coolify (via son proxy Traefik) route le trafic vers le port 80 du service web.
  • Les variables DB_HOST, DB_NAME, DB_USER et DB_PASSWORD sont celles lues par le code PHP (étape 1). DB_HOST vaut database : c'est le nom du service MariaDB dans ce fichier.
  • Les ${VARIABLE} seront renseignées dans Coolify (partie C). ${VARIABLE:-valeur} définit une valeur par défaut.
  • Le fichier database.sql (étape suivante) est importé une seule fois, à la première création de la base.
  • Projet sans base de données : ne garder que le service web (sans environment ni depends_on), et supprimer la section volumes.

5. database.sql​

Si le projet utilise une base de données, exporter sa structure et ses données dans un fichier database.sql à la racine du projet (export depuis phpMyAdmin, ou mysqldump).

Explications :

  • Au tout premier démarrage de la base dans Coolify (volume vide), MariaDB exécute ce fichier et crée les tables.
  • Le fichier ne doit pas contenir d'instruction CREATE DATABASE ni USE nom_de_la_base : la base app est déjà créée par Coolify. Dans phpMyAdmin, décocher l'option de création de la base dans les options d'export.
  • Ce fichier est exclu de l'image par le .dockerignore : il n'est donc pas téléchargeable depuis le site.
  • Après la première mise en ligne, les modifications de la structure de la base ne sont pas rejouées automatiquement (voir « MAJ du projet par l'étudiant », étape 5.2).

B) Pousser les modifications sur GitHub​

git status
git add Dockerfile compose.yaml .dockerignore database.sql config.php
git commit -m "Préparer le déploiement Coolify (PHP, Apache, MariaDB)"
git push origin main

Explications :

  • Coolify déploie ce qui est sur GitHub : tous les fichiers créés ou modifiés en A doivent être poussés sur la branche main. Ajouter aussi les autres fichiers modifiés (git add . convient si .gitignore est correct).
  • git status permet de vérifier la liste des fichiers modifiés avant le git add.
  • Le dépôt doit être public, car la ressource Coolify est de type Public Repository.
  • Ne jamais committer de secrets : le fichier .env doit figurer dans le .gitignore, et les mots de passe de production se définissent dans Coolify (partie C).

MAJ du projet par l'étudiant​

Après chaque modification du projet PHP, suivre ces étapes dans l'ordre.

5.1 Tester en local​

php -S localhost:8000

Ouvrir http://localhost:8000/ et vérifier que le site fonctionne avant de pousser.

5.2 Si la structure de la base de données a changé​

  • Mettre à jour le fichier database.sql pour de futures installations (nouvel export, voir A, étape 5).
  • Pour la base déjà en ligne, database.sql n'est pas rejoué : écrire dans un fichier ou un message à l'enseignant les requêtes SQL à exécuter (par exemple ALTER TABLE projets ADD COLUMN lien VARCHAR(255);). L'enseignant les exécute dans le conteneur database (voir « MAJ du projet par l'enseignant », étape 5.6).
  • Les données de la base sont conservées entre les déploiements (volume database_data).

5.3 Si des dépendances ont changé​

composer require vendor/paquet

composer require modifie composer.json et composer.lock : les deux fichiers doivent être committés. Le dossier vendor/ n'est pas committé : il est régénéré pendant le build (étape 1 du Dockerfile).

5.4 Pousser les modifications sur GitHub​

git status
git add .
git commit -m "Description de la modification"
git push origin main

Vérifier avec git status qu'aucun secret (.env) n'est ajouté.

Attendre la fin du git push avant de demander le déploiement dans Coolify : Coolify déploie le dernier commit présent sur GitHub, pas celui de votre poste. Pour vérifier que le push est bien terminé :

git status

Le message doit indiquer Your branch is up to date with 'origin/main'.

Puis prévenir l'enseignant, qui lance le déploiement (voir « MAJ du projet par l'enseignant »).


C) Créer la ressource dans Coolify​

1. Créer la ressource​

  1. Projet → choisir l'environnement (ex. 2026-sio2-portfolio) → + New Resource.

  2. Choisir Public Repository.

  3. Saisir l'URL du dépôt dans l'unique champ Repository URL (https://) : https://github.com/votre-compte/mon-portfolio, puis valider (Check repository).

  4. Sur l'écran suivant, renseigner la configuration de la ressource :

    • Branch : main
    • Build Pack : Docker Compose
    • Base Directory : /
    • Docker Compose Location : /compose.yaml
  5. Cliquer sur Continue : la ressource est créée et ouverte sur sa page Configuration.

2. Variables d'environnement​

Dans la ressource, onglet Environment Variables :

  1. Coolify détecte les ${VARIABLE} du compose.yaml et les liste. Si une variable manque, cliquer sur + Add.

  2. Renseigner la valeur de chaque variable (Key / Value) :

    VariableValeur
    MARIADB_PASSWORDvaleur aléatoire (mot de passe de l'utilisateur applicatif)
    MARIADB_ROOT_PASSWORDvaleur aléatoire (mot de passe root MariaDB)

    Ces deux valeurs sont des secrets : chacune doit être générée de façon aléatoire et différente de l'autre. Ne jamais copier/coller celles d'un exemple, d'un tutoriel ou d'un autre projet, ni les committer dans Git.

    Pour générer une valeur aléatoire (valable sous Windows, Linux et macOS, car PHP est déjà installé) :

    php -r "echo bin2hex(random_bytes(32));"

    Lancer la commande une fois par variable et copier chaque résultat dans la valeur correspondante. Aucun besoin de retenir ces valeurs : seule l'application les utilise, et elles restent stockées dans Coolify. Le format hexadécimal évite les caractères spéciaux.

    MariaDB ne lit MARIADB_PASSWORD et MARIADB_ROOT_PASSWORD qu'à la première création de la base (volume vide). Les modifier ensuite dans Coolify ne change pas les mots de passe déjà enregistrés dans la base.

    MARIADB_USER, MARIADB_DATABASE et MARIADB_VERSION ont une valeur par défaut dans le compose.yaml : ne les définir que pour la changer.

    ATTENTION : Saisir la valeur aléatoire à droite du nom de la variable (pas dans le champ Comment) dans le champ avec un oeil.

  3. Pour enregistrer chaque variable, cliquer sur le bouton Update situé sur sa ligne. Une variable saisie mais non enregistrée avec Update est perdue.

Les variables ne sont prises en compte qu'au prochain déploiement.

3. Définir le sous-domaine​

  1. Dans l'onglet General, le champ Domains apparaît pour chaque service du compose. Pour le service web, saisir par exemple :

    https://portfolio-php-demo.app.ndlpavranches.fr

    Apache écoute sur le port 80 : il n'y a pas de port à ajouter. Ne rien saisir pour le service database, qui ne doit pas être accessible depuis Internet.

  2. Cliquer sur Save. Coolify génère le routage Traefik et le certificat Let's Encrypt.

  3. Chez le gestionnaire DNS du domaine, créer un enregistrement de type A pour ce sous-domaine, pointant vers l'adresse IP du serveur Coolify.


D) Déployer​

Cliquer sur Deploy (en haut de la ressource), puis suivre les logs du déploiement. Une fois terminé, le site est accessible à l'adresse du sous-domaine.

Dépannage : « dependency failed to start: container database … is unhealthy »​

Ouvrir les logs du conteneur database (onglet Logs de la ressource). Si on y lit :

Database is uninitialized and password option is not specified

alors MARIADB_ROOT_PASSWORD (ou MARIADB_PASSWORD) est vide ou absent : MariaDB refuse de démarrer sans mot de passe. Pour corriger :

  1. Onglet Environment Variables : vérifier que MARIADB_ROOT_PASSWORD et MARIADB_PASSWORD ont chacune une valeur (voir C, étape 2).
  2. Cliquer sur Update sur chaque ligne modifiée.
  3. Cliquer de nouveau sur Deploy.

Si le conteneur database a déjà démarré une fois avec de mauvais mots de passe, supprimer le volume database_data de la ressource avant de redéployer (MariaDB ne relit les mots de passe qu'à la première initialisation). Attention : cela efface les données de la base.

Dépannage : page blanche, ou erreur 500​

Les erreurs PHP ne sont pas affichées aux visiteurs en production. Les lire dans les logs du conteneur web (onglet Logs de la ressource).

Dépannage : « SQLSTATE[HY000] [2002] » ou « getaddrinfo for localhost failed »​

Le code PHP cherche la base sur localhost au lieu de database. Vérifier que le code lit bien getenv('DB_HOST') (voir A, étape 1) et qu'aucun nom de serveur n'est écrit en dur dans un autre fichier.

Dépannage : « Access denied for user »​

Les identifiants lus par le code ne correspondent pas à ceux de la base. Vérifier les noms DB_USER, DB_PASSWORD et DB_NAME dans le code et dans le compose.yaml. Si les mots de passe ont été modifiés dans Coolify après le premier déploiement, supprimer le volume database_data (voir le dépannage précédent : cela efface les données) ou modifier les mots de passe directement dans MariaDB.

Dépannage : « Table doesn't exist »​

Le fichier database.sql n'a pas été importé : il n'est exécuté qu'à la première création de la base. Vérifier qu'il est bien sur GitHub, à la racine du projet. S'il a été ajouté après le premier déploiement, supprimer le volume database_data (cela efface les données) avant de redéployer.


MAJ du projet par l'enseignant​

Après chaque modification du projet PHP, suivre ces étapes dans l'ordre.

5.5 Redéployer dans Coolify​

Dans la ressource Coolify :

  • dans l'onglet General, cliquer sur le bouton Reload Compose file

  • cliquer sur le bouton Deploy (en haut à droite), puis suivre les logs du déploiement.

  • Coolify récupère le dernier commit de la branche main, reconstruit l'image du service web et redémarre les conteneurs. Les données de la base sont conservées.

  • Le déploiement n'est pas lancé automatiquement par un git push : il faut cliquer sur Deploy.

  • Si seules des variables d'environnement ont changé (onglet Environment Variables, bouton Update), aucun git push n'est nécessaire : cliquer directement sur Deploy.

  • Au début du log de déploiement, la ligne Importing votre-compte/mon-portfolio:main (commit sha …) indique le commit réellement déployé. Il doit correspondre au dernier commit poussé par l'étudiant (git log -1 --format=%H). Sinon, le déploiement a été lancé trop tôt : relancer Deploy.

5.6 Si la structure de la base a changé : exécuter les requêtes SQL​

Ouvrir un terminal dans le conteneur database (onglet Terminal de la ressource, choisir le service database), puis se connecter :

mariadb -u root -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE"

Coller les requêtes SQL fournies par l'étudiant (par exemple ALTER TABLE ...;), puis quitter avec exit.

5.7 Vérifier​

  • Ouvrir le site à l'adresse du sous-domaine et tester la modification.
  • En cas d'erreur, consulter les logs du déploiement, puis les logs du conteneur web dans Coolify.