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
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()remplaceload():load()provoque une erreur si le fichier.envest absent, ce qui serait le cas en production.getenv()lit les variables fournies par Coolify. La lecture dans$_ENVseule ne suffit pas, car en production$_ENVest vide (voir leDockerfile, é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'appelledatabase, et le mot de passe est secret. - Si le projet n'utilise pas Composer ni
phpdotenv, supprimer les deux premières instructions et lire uniquementgetenv('DB_HOST'), etc. - Si le projet n'a pas de base de données, passer cette étape et supprimer le service
databasedans 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 mysqliajoute les extensions PHP pour accéder à MariaDB (pdo_mysqlpour PDO,mysqlisi le projet l'utilise).php.ini-productionest 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 degetenv()à l'étape 1.- La première étape installe les bibliothèques (dossier
vendor/) avec Composer, sans les paquets de développement. Les fichierscomposer.jsonetcomposer.lockdoivent ê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
.htaccessn'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/duDockerfile. - 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/.envouhttps://votre-site/database.sqlseraient accessibles. vendor/est exclu car il est reconstruit par Composer à l'étape 1 duDockerfile.
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 servicewebest construite à partir duDockerfilesitué à la racine du projet.- Aucun
ports:n'est publié : Coolify (via son proxy Traefik) route le trafic vers le port 80 du serviceweb. - Les variables
DB_HOST,DB_NAME,DB_USERetDB_PASSWORDsont celles lues par le code PHP (étape 1).DB_HOSTvautdatabase: 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(sansenvironmentnidepends_on), et supprimer la sectionvolumes.
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 DATABASEniUSE nom_de_la_base: la baseappest 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.gitignoreest correct). git statuspermet de vérifier la liste des fichiers modifiés avant legit add.- Le dépôt doit être public, car la ressource Coolify est de type Public Repository.
- Ne jamais committer de secrets : le fichier
.envdoit 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.sqlpour de futures installations (nouvel export, voir A, étape 5). - Pour la base déjà en ligne,
database.sqln'est pas rejoué : écrire dans un fichier ou un message à l'enseignant les requêtes SQL à exécuter (par exempleALTER TABLE projets ADD COLUMN lien VARCHAR(255);). L'enseignant les exécute dans le conteneurdatabase(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
-
Projet → choisir l'environnement (ex. 2026-sio2-portfolio) → + New Resource.
-
Choisir Public Repository.
-
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). -
Sur l'écran suivant, renseigner la configuration de la ressource :
- Branch :
main - Build Pack : Docker Compose
- Base Directory :
/ - Docker Compose Location :
/compose.yaml
- Branch :
-
Cliquer sur Continue : la ressource est créée et ouverte sur sa page Configuration.
2. Variables d'environnement
Dans la ressource, onglet Environment Variables :
-
Coolify détecte les
${VARIABLE}ducompose.yamlet les liste. Si une variable manque, cliquer sur + Add. -
Renseigner la valeur de chaque variable (Key / Value) :
Variable Valeur 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_PASSWORDetMARIADB_ROOT_PASSWORDqu'à 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_DATABASEetMARIADB_VERSIONont une valeur par défaut dans lecompose.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. -
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
-
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.frApache é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. -
Cliquer sur Save. Coolify génère le routage Traefik et le certificat Let's Encrypt.
-
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 :
- Onglet Environment Variables : vérifier que
MARIADB_ROOT_PASSWORDetMARIADB_PASSWORDont chacune une valeur (voir C, étape 2). - Cliquer sur Update sur chaque ligne modifiée.
- 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.