Chapitre 4.2 — Environnement de développement avec moodle-docker
Dans le chapitre précédent, nous avons passé en revue les prérequis techniques de Moodle 5.2 : PHP 8.3 minimum, une base de données PostgreSQL 16+, MySQL 8.4+ ou MariaDB 10.11+, un serveur web, et toute une série d’extensions PHP. Installer tout cela à la main sur une machine Windows, c’est possible… mais c’est long, fragile, et surtout ce n’est pas ce que font les développeurs Moodle professionnels au quotidien.
La communauté Moodle — et plus précisément Moodle HQ, l’entreprise qui pilote le développement du projet — maintient un outil officiel qui règle ce problème une bonne fois pour toutes : moodle-docker. C’est l’équivalent, dans l’écosystème Moodle, de ce que serait un docker-compose.yml de référence maintenu par Vercel pour développer sur Next.js : un environnement complet, reproductible, identique à celui utilisé par l’intégration continue du projet, que vous montez et démontez en quelques commandes.
Ce chapitre est volontairement long et détaillé : c’est le chapitre fondateur de votre pratique quotidienne. Tout ce que nous ferons dans la suite de cette documentation (développement de plugins, thèmes, tests automatisés) reposera sur l’environnement que nous allons construire ici. Prenez le temps de le suivre pas à pas, commandes comprises — à la fin, vous aurez un Moodle 5.2 complet qui tourne sur votre machine Windows 11, avec interception des e-mails, tests Behat/PHPUnit prêts à l’emploi, et un cycle de vie que vous maîtriserez entièrement.
💡 Pour un dev React : si vous venez du monde Next.js, gardez cette grille de lecture en tête pendant tout le chapitre :
moodle-docker≈ votredocker-compose.ymlde dev +npm run dev,config.docker-template.php≈ votre.env.local,install_database.php≈ vos migrations + seed (prisma migrate dev+prisma db seed), et Mailpit ≈ l’onglet “Emails” de Resend en mode test. Rien de conceptuellement nouveau — juste des noms différents.
Mini-sommaire
- Pourquoi moodle-docker ?
- Prérequis sur Windows 11 : WSL2 + Docker Desktop
- Mise en place pas à pas
- Vérifications post-installation
- Comptes et données de test
- Mailpit : intercepter les e-mails
- Behat, Selenium et PHPUnit
- Cycle de vie de l’environnement
- Personnalisation avec local.yml
- Spécificités Windows / WSL2
- Alternative rapide : l’image bitnami/moodle
- Tableau récapitulatif des commandes
1. Pourquoi moodle-docker ?
1.1 Ce que c’est
moodle-docker est un dépôt Git maintenu par Moodle HQ. Techniquement, ce n’est pas une image Docker : c’est un wrapper autour de Docker Compose. Le dépôt contient une collection de fichiers *.yml (un fichier de base, plus des fragments conditionnels pour chaque base de données, pour Selenium, pour l’app mobile…) et un script principal, bin/moodle-docker-compose, qui assemble dynamiquement la bonne combinaison de fichiers Compose en fonction de variables d’environnement que vous définissez.
Autrement dit, quand vous tapez :
bin/moodle-docker-compose up -dle script lit vos variables (MOODLE_DOCKER_DB=pgsql, MOODLE_DOCKER_PHP_VERSION=8.3, etc.), sélectionne les fragments YAML correspondants, et exécute en réalité quelque chose comme docker compose -f base.yml -f db.pgsql.yml -f selenium.yml ... up -d. C’est exactement le mécanisme des overrides Docker Compose (-f fichier1.yml -f fichier2.yml), mais orchestré pour vous.
Ce détail a une conséquence importante : la même commande bin/moodle-docker-compose accepte toutes les sous-commandes de Docker Compose (up, down, stop, start, logs, exec, ps, restart…). Vous n’apprenez rien de nouveau, vous réutilisez ce que vous savez déjà de Docker.
Point crucial pour la confiance : moodle-docker n’est pas un projet communautaire de plus. C’est l’environnement utilisé par l’intégration continue de Moodle lui-même. Quand un correctif est proposé sur le tracker Moodle, les tests Behat et PHPUnit qui le valident tournent dans ces conteneurs. En l’utilisant, vous développez dans les mêmes conditions que les mainteneurs du projet — ce qui élimine toute une classe de bugs du type « ça marche chez moi ».
1.2 Ce qu’il fournit
Une fois lancé, moodle-docker démarre une petite constellation de conteneurs :
| Conteneur | Rôle |
|---|---|
webserver | Apache + PHP (image moodlehq/moodle-php-apache), sert votre code Moodle monté en volume |
db | La base de données de votre choix : PostgreSQL, MariaDB, MySQL, SQL Server ou Oracle |
mailpit | Un serveur SMTP factice avec interface web : tous les e-mails sortants y sont capturés |
selenium | Un navigateur (Firefox ou Chrome) pilotable à distance, pour les tests Behat |
exttests | Un petit serveur web servant des fixtures pour certains tests unitaires (services externes simulés) |
Le point clé : votre code Moodle vit sur votre disque, dans un dossier que vous choisissez, et il est monté en volume dans le conteneur webserver. Vous éditez les fichiers avec VS Code, la modification est visible instantanément dans le conteneur. Aucune reconstruction d’image, aucun docker cp.
💡 Pour un dev React : c’est le même modèle mental que
next devavec le hot reload, à une nuance près : PHP n’a pas besoin de watcher ni de rebuild. Chaque requête HTTP relit les fichiers PHP depuis le disque (modulo le cache d’opcode, désactivé de façon adaptée en dev). Vous sauvegardez dans VS Code, vous rafraîchissez le navigateur, c’est tout. Pas de HMR, mais pas non plus de compilation à attendre — sauf pour le JavaScript et le CSS de Moodle, qui ont leur propre pipeline de build (Grunt) que nous verrons dans un chapitre ultérieur.
1.3 Ce que ce n’est PAS
Disons-le clairement, car la question revient systématiquement : moodle-docker n’est pas un outil de production, et le README du projet le martèle. Il n’y a pas de HTTPS, la base de données a des mots de passe triviaux codés en dur (moodle/m@0dl3ing), les e-mails sont interceptés au lieu d’être envoyés, aucun mécanisme de sauvegarde ni de haute disponibilité n’est prévu, et les données peuvent être détruites par une simple commande down. C’est un environnement de développement et de test, point final. Le déploiement en production fera l’objet d’un chapitre dédié, avec des outils différents.
⚠️ Piège : ne cédez pas à la tentation d’exposer votre moodle-docker sur Internet « juste pour montrer à un collègue ». Par défaut le port n’est lié qu’à
127.0.0.1, et c’est voulu. Si vous avez besoin de partager un site de démonstration, utilisez un tunnel éphémère (Cloudflare Tunnel, ngrok) ou un vrai hébergement.
2. Prérequis sur Windows 11 : WSL2 + Docker Desktop
2.1 Pourquoi WSL2, et pourquoi le code doit vivre DANS WSL2
Docker Desktop sur Windows 11 fonctionne (par défaut) avec le backend WSL2 : le démon Docker tourne en réalité dans une machine virtuelle Linux légère gérée par Windows Subsystem for Linux. C’est le mode recommandé, performant et bien intégré.
Mais il y a une règle d’or que beaucoup de développeurs découvrent trop tard, après des heures de frustration :
⚠️ Piège (LE piège numéro un sur Windows) : votre code Moodle doit vivre dans le système de fichiers Linux de WSL2 (par exemple
~/moodledans Ubuntu), et jamais sur le disque Windows monté (/mnt/c/Users/...). La raison est purement une question de performances : les accès aux fichiers de/mnt/cpassent par le protocole 9P entre Windows et la VM WSL2, avec un coût de latence énorme par opération. Or Moodle, c’est plus de 25 000 fichiers PHP. Une page qui se charge en 300 ms avec le code sous~/peut prendre 15 à 60 secondes avec le code sous/mnt/c. Ce n’est pas une exagération : c’est l’écart réellement mesuré. Ungit statusqui prend 0,1 s d’un côté en prend 30 de l’autre. Mettez le code dans WSL2, éditez-le avec VS Code Remote-WSL (section 10), et tout sera fluide.
Concrètement, l’architecture cible ressemble à ceci :
Windows 11
├── Docker Desktop (interface graphique, gestion)
│ └── backend WSL2 (le démon Docker tourne ici)
├── VS Code (l'interface tourne sous Windows)
│ └── extension Remote-WSL → édite les fichiers DANS Ubuntu
└── WSL2 / Ubuntu
├── ~/moodle-docker ← le clone de l'outil
└── ~/moodle ← le clone du code Moodle 5.2Tout ce qui est fichiers et commandes se passe dans Ubuntu. Windows ne sert que d’hôte pour l’affichage (VS Code, navigateur) et pour Docker Desktop.
2.2 Installer WSL2 et Ubuntu (si ce n’est pas déjà fait)
Sur un Windows 11 à jour, l’installation de WSL2 tient en une commande. Ouvrez un terminal PowerShell en administrateur (clic droit sur le menu Démarrer → « Terminal (administrateur) ») :
wsl --installCette commande active les fonctionnalités Windows nécessaires (plateforme de machine virtuelle, sous-système Linux), télécharge le noyau WSL2 et installe la distribution Ubuntu par défaut. Redémarrez la machine quand on vous le demande.
Au premier lancement d’Ubuntu (cherchez « Ubuntu » dans le menu Démarrer), on vous demandera de créer un utilisateur Linux et un mot de passe — ils sont indépendants de votre compte Windows.
Si WSL est déjà installé mais ancien, mettez-le à jour et vérifiez que vous êtes bien en version 2 :
wsl --update
wsl --list --verboseLa colonne VERSION doit afficher 2 pour Ubuntu. Si elle affiche 1 :
wsl --set-version Ubuntu 2Enfin, quelques réglages de confort dans Ubuntu (mise à jour des paquets, installation de Git s’il manque) :
# Dans le terminal Ubuntu (WSL2)
sudo apt update && sudo apt upgrade -y
sudo apt install -y git2.3 Installer Docker Desktop avec le backend WSL2
- Téléchargez Docker Desktop pour Windows depuis docker.com et installez-le. Pendant l’installation, laissez cochée l’option « Use WSL 2 instead of Hyper-V ».
- Lancez Docker Desktop. Dans Settings → General, vérifiez que « Use the WSL 2 based engine » est activé.
- Dans Settings → Resources → WSL Integration, activez l’intégration pour votre distribution Ubuntu. C’est ce réglage qui rend la commande
dockerdisponible à l’intérieur du terminal Ubuntu.
Vérifiez ensuite, depuis le terminal Ubuntu :
docker --version # doit afficher >= 20.10.15
docker compose version # doit afficher >= 2.5.0
docker run --rm hello-worldmoodle-docker exige officiellement Docker ≥ 20.10.15 et Docker Compose ≥ 2.5.0. Toute installation récente de Docker Desktop dépasse largement ces versions, mais si vous héritez d’une vieille installation, c’est le moment de la mettre à jour.
💡 Pour un dev React : Docker Desktop avec l’intégration WSL, c’est comme avoir Node installé dans un seul runtime partagé : la CLI
dockerque vous tapez dans Ubuntu parle au même démon que celle de PowerShell. Les images et conteneurs sont communs. En revanche, les fichiers montés en volume, eux, sont sensibles à leur emplacement — d’où la règle de la section 2.1.
📚 Aller plus loin : la documentation Microsoft sur WSL (learn.microsoft.com/windows/wsl) et le guide « Docker Desktop WSL 2 backend » (docs.docker.com/desktop/wsl) détaillent les options avancées : limitation de la RAM allouée à WSL via
.wslconfig,systemddans WSL, etc.
3. Mise en place pas à pas
Nous y sommes. Toutes les commandes de cette section s’exécutent dans le terminal Ubuntu (WSL2), sauf mention contraire. Les équivalents PowerShell sont donnés à titre informatif pour les (rares) cas où vous voudriez travailler nativement sous Windows — ce que nous déconseillons pour les raisons de performance vues plus haut, mais qui reste techniquement supporté par moodle-docker.
3.1 Étape 1 — Cloner moodle-docker
cd ~
git clone https://github.com/moodlehq/moodle-docker.git
cd moodle-dockerLe dépôt est minuscule (quelques centaines de kilo-octets) : rappelez-vous, ce ne sont que des fichiers YAML et des scripts shell. Jetez un œil à sa structure :
ls
# assets/ bin/ config.docker-template.php base.yml db.pgsql.yml db.mariadb.yml ...
ls bin/
# moodle-docker-compose moodle-docker-wait-for-db ...⚠️ Piège : gardez ce clone à jour (
git pullrégulier). Ce n’est pas un conseil cosmétique : depuis Moodle 5.1, le code web de Moodle a déménagé dans un sous-dossierpublic/, et ce sont les images récentesmoodlehq/moodle-php-apacheréférencées par moodle-docker qui détectent la présence de ce dossier et ajustent automatiquement leDocumentRootd’Apache. Avec un vieux clone de moodle-docker (donc de vieilles références d’images), un Moodle 5.2 fraîchement cloné vous servirait une erreur ou une arborescence de fichiers au lieu du site. Ungit pulldans~/moodle-dockerde temps en temps vous épargne ce genre de mystère.
3.2 Étape 2 — Cloner Moodle 5.2
Moodle 5.2 (sorti le 20 avril 2026) vit sur la branche stable MOODLE_502_STABLE. Deux dépôts officiels équivalents existent :
https://github.com/moodle/moodle.git— le miroir GitHub, généralement le plus rapide ;https://git.moodle.org/moodle.git— le dépôt canonique historique.
Ils sont synchronisés ; prenez GitHub par défaut.
Deux stratégies de clonage s’offrent à vous :
Option A — clone superficiel (rapide, pour découvrir) :
git clone -b MOODLE_502_STABLE --depth 1 https://github.com/moodle/moodle.git ~/moodle--depth 1 ne télécharge que le dernier commit de la branche : comptez quelques centaines de Mo et une à deux minutes. Parfait pour un premier contact.
Option B — clone complet (recommandé si vous comptez développer sérieusement) :
git clone -b MOODLE_502_STABLE https://github.com/moodle/moodle.git ~/moodleLe dépôt complet de Moodle est volumineux — l’historique remonte à 2001, et le .git pèse plusieurs gigaoctets. Mais si vous envisagez de contribuer au cœur de Moodle, ou simplement de faire du git log/git blame/git bisect sur le code (ce qui est une façon formidable de comprendre pourquoi une ligne existe), l’historique complet est indispensable. Vous pourrez aussi basculer entre branches stables (MOODLE_500_STABLE, main…) sans re-cloner. Un --depth 1 peut être « approfondi » plus tard avec git fetch --unshallow, mais autant partir du bon pied si votre connexion le permet.
💡 Pour un dev React :
MOODLE_502_STABLEjoue le rôle d’une branche de release maintenue, comme les branchesv14.xd’un gros projet Node. Elle reçoit les correctifs de bugs et de sécurité de la série 5.2 ;git pulldessus équivaut à monter de 5.2.0 à 5.2.1, jamais à changer de version majeure. La branchemain, elle, est l’équivalent decanary: c’est là que se prépare la version suivante.
Vérifiez au passage la nouveauté structurelle de Moodle 5.x :
ls ~/moodle
# config-dist.php public/ lib/ ... (selon la version exacte)
ls ~/moodle/public
# admin/ course/ index.php lib/ login/ mod/ theme/ ...Depuis Moodle 5.1, le code servi par le web vit dans public/, tandis que config.php reste à la racine du projet. Conséquence pratique que vous utiliserez cent fois : les scripts CLI se lancent désormais avec le préfixe public/, par exemple php public/admin/cli/purge_caches.php depuis la racine du dépôt. Beaucoup de tutoriels antérieurs à 2025 écrivent php admin/cli/... — pensez à ajouter public/ mentalement quand vous en croisez.
3.3 Étape 3 — Définir les variables d’environnement
moodle-docker se configure entièrement par variables d’environnement. Deux sont obligatoires :
| Variable | Rôle | Valeurs |
|---|---|---|
MOODLE_DOCKER_WWWROOT | Chemin du code Moodle sur votre machine | ex. /home/alex/moodle |
MOODLE_DOCKER_DB | Moteur de base de données | pgsql, mariadb, mysql, mssql, oracle |
Et les principales optionnelles :
| Variable | Défaut | Rôle |
|---|---|---|
MOODLE_DOCKER_PHP_VERSION | 8.3 | Version de PHP du conteneur web (8.4 supporté pour Moodle 5.2) |
MOODLE_DOCKER_WEB_PORT | 127.0.0.1:8000 | Port (et interface) d’écoute du serveur web |
MOODLE_DOCKER_DB_PORT | (non exposé) | Expose le port de la DB sur l’hôte (ex. 5432) |
MOODLE_DOCKER_BROWSER | firefox | Navigateur Selenium pour Behat (chrome possible, tags de version acceptés, ex. firefox:135) |
MOODLE_DOCKER_SELENIUM_VNC_PORT | (désactivé) | Expose le VNC de Selenium pour regarder les tests (ex. 5900) |
MOODLE_DOCKER_APP_PATH / MOODLE_DOCKER_APP_VERSION | (désactivé) | Lance un conteneur de l’app mobile Moodle pour la tester |
Pour ce chapitre, nous choisissons PostgreSQL (le moteur de référence de la CI Moodle et celui que nous recommandons en dev) :
export MOODLE_DOCKER_WWWROOT=~/moodle
export MOODLE_DOCKER_DB=pgsqlCes export ne valent que pour la session de terminal courante. Pour ne pas devoir les retaper à chaque fois, persistez-les dans votre ~/.bashrc :
cat >> ~/.bashrc <<'EOF'
# --- moodle-docker ---
export MOODLE_DOCKER_WWWROOT="$HOME/moodle"
export MOODLE_DOCKER_DB=pgsql
EOF
source ~/.bashrcÉquivalent PowerShell (si vous travailliez nativement sous Windows, code sur le disque Windows — rappel : performances dégradées) :
$env:MOODLE_DOCKER_WWWROOT = "C:\Users\Alexl\moodle"
$env:MOODLE_DOCKER_DB = "pgsql"Et pour persister côté Windows (variables utilisateur permanentes) :
[Environment]::SetEnvironmentVariable("MOODLE_DOCKER_WWWROOT", "C:\Users\Alexl\moodle", "User")
[Environment]::SetEnvironmentVariable("MOODLE_DOCKER_DB", "pgsql", "User")⚠️ Piège :
MOODLE_DOCKER_WWWROOTdoit pointer vers la racine du dépôt Moodle (le dossier qui contientpublic/et où vivraconfig.php), pas verspublic/lui-même. Si vous pointez surpublic/, le montage sera incohérent et l’installation échouera de façon peu lisible.
💡 Pour un dev React : ce jeu de variables d’environnement remplit exactement le rôle des variables de votre
.envde projet Compose. moodle-docker a choisi les variables d’environnement du shell plutôt qu’un fichier.envpour une raison simple : c’est le même mécanisme sur la CI (GitHub Actions exporte des variables, pas des fichiers). Rien ne vous empêche cependant de créer un petit script~/moodle-env.shà sourcer, si vous jonglez entre plusieurs configurations.
3.4 Étape 4 — Copier config.docker-template.php
cp ~/moodle-docker/config.docker-template.php ~/moodle/config.phpOuvrez ce fichier, il mérite deux minutes de lecture. Il ne contient aucune valeur en dur : il lit les variables d’environnement injectées dans le conteneur par Docker Compose. Extrait représentatif (simplifié) :
<?php // Moodle configuration file
unset($CFG);
global $CFG;
$CFG = new stdClass();
$CFG->dbtype = getenv('MOODLE_DOCKER_DBTYPE');
$CFG->dblibrary = 'native';
$CFG->dbhost = 'db';
$CFG->dbname = getenv('MOODLE_DOCKER_DBNAME');
$CFG->dbuser = getenv('MOODLE_DOCKER_DBUSER');
$CFG->dbpass = getenv('MOODLE_DOCKER_DBPASS');
$host = 'localhost';
if (!empty(getenv('MOODLE_DOCKER_WEB_HOST'))) {
$host = getenv('MOODLE_DOCKER_WEB_HOST');
}
$CFG->wwwroot = "http://{$host}";
$port = getenv('MOODLE_DOCKER_WEB_PORT');
// ... ajout du port au wwwroot si nécessaire ...
$CFG->dataroot = '/var/www/moodledata';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
// Configuration PHPUnit et Behat pré-câblée vers les conteneurs :
$CFG->phpunit_dataroot = '/var/www/phpunitdata';
$CFG->behat_dataroot = '/var/www/behatdata';
$CFG->behat_wwwroot = 'http://webserver';
// ...
require_once(__DIR__ . '/lib/setup.php'); // ou public/lib selon la version du templateTrois choses à retenir :
dbhost = 'db': dans le réseau Docker Compose, chaque service est joignable par son nom. Le conteneur web parle à la base via le hostnamedb, pas vialocalhost.- Tout vient de l’environnement : c’est le fichier Compose qui injecte
MOODLE_DOCKER_DBTYPE,MOODLE_DOCKER_DBNAME, etc. dans le conteneur. Vous ne modifiez donc jamais ceconfig.phppour changer de DB : vous changez la variable côté hôte et relancez. - Behat et PHPUnit sont déjà configurés : les sections correspondantes pointent vers les bons répertoires et vers le conteneur Selenium. C’est un énorme gain par rapport à une installation manuelle, où cette configuration est la principale source d’erreurs des débutants.
💡 Pour un dev React :
config.docker-template.phpest le.env.localde Moodle — à ceci près que Moodle n’a pas de mécanisme.envnatif :config.phpest le fichier de config, et c’est du PHP exécutable. Le template choisit de déléguer toutes les valeurs àgetenv(), exactement comme unnext.config.jsqui liraitprocess.env. Et comme un.env.local, ceconfig.phpde dev ne doit jamais être commité : il est d’ailleurs couvert par le.gitignorede Moodle.
3.5 Étape 5 — Démarrer les conteneurs
cd ~/moodle-docker
bin/moodle-docker-compose up -dAu premier lancement, Docker télécharge les images (moodlehq/moodle-php-apache, postgres, mailpit, selenium…) : comptez quelques minutes selon votre connexion. Les fois suivantes, le démarrage prend quelques secondes.
Puis attendez que la base de données soit réellement prête à accepter des connexions :
bin/moodle-docker-wait-for-db⚠️ Piège : ne sautez pas
wait-for-db.up -drend la main dès que les conteneurs sont démarrés, pas quand PostgreSQL a fini son initialisation interne. Si vous enchaînez immédiatement sur l’installation de la base, vous récolterez une erreur de connexion intermittente — le genre d’erreur qui marche une fois sur deux et rend fou. Ce script fait exactement ce que ferait unhealthcheck+depends_on: condition: service_healthy: il sonde la DB jusqu’à ce qu’elle réponde.
3.6 Étape 6 — Installer la base de données Moodle
Le code est en place, les conteneurs tournent, la DB est vide. Il reste à exécuter l’installeur CLI de Moodle à l’intérieur du conteneur web :
bin/moodle-docker-compose exec webserver php public/admin/cli/install_database.php \
--agree-license \
--fullname="Moodle Dev" \
--shortname="moodle_dev" \
--summary="Site de dev" \
--adminpass="test" \
--adminemail="admin@example.com"Décortiquons chaque élément, car cette commande condense beaucoup de concepts :
bin/moodle-docker-compose exec webserver: « exécute la commande qui suit dans le conteneurwebserver» — l’équivalent exact dedocker compose exec webserver.php public/admin/cli/install_database.php: le script d’installation, lancé depuis la racine du code (/var/www/htmldans le conteneur). Notez le préfixepublic/, signature de Moodle 5.1+.--agree-license: accepte la licence GPL sans question interactive. Sans ce flag, le script vous la ferait défiler et demanderait confirmation.--fullname="Moodle Dev": le nom complet du site, affiché en page d’accueil et dans les titres.--shortname="moodle_dev": le nom court, utilisé dans le fil d’Ariane et les sujets d’e-mails.--summary="Site de dev": la description de la page d’accueil (optionnel, peut rester vide).--adminpass="test": le mot de passe du compte administrateur.testest acceptable uniquement parce que ce site n’écoute que sur127.0.0.1. L’installeur CLI ne soumet pas ce mot de passe à la politique de complexité du site — ne prenez évidemment jamais cette habitude ailleurs.--adminemail="admin@example.com": l’adresse du compte admin. Comme Mailpit intercepte tout, elle peut être fictive.
Deux options supplémentaires méritent d’être connues :
--adminuser="admin": le nom d’utilisateur du compte admin (défaut :admin). Utile si vous voulez un identifiant différent.--supportemail="support@example.com": l’adresse de support affichée aux utilisateurs dans les e-mails et pages d’aide (optionnel).
Le script déroule alors la création des ~500 tables de Moodle et l’insertion des données initiales ; comptez une à deux minutes. À la fin, il affiche Installation completed successfully.
💡 Pour un dev React :
install_database.phpcumule ce que vous connaissez sous deux formes séparées : la migration (création du schéma — pensezprisma migrate deploy) et le seed minimal (site, cours d’accueil, compte admin — pensezprisma db seed). Le schéma n’est pas décrit en SQL mais dans des fichiers XML (db/install.xml) propres à chaque composant de Moodle, interprétés par une couche d’abstraction (XMLDB) qui génère le SQL adapté au moteur choisi. Nous y reviendrons longuement dans le chapitre sur le développement de plugins.
3.7 Étape 7 — Premier login
Ouvrez votre navigateur Windows (oui, Windows : les ports publiés par Docker Desktop dans WSL2 sont automatiquement accessibles depuis l’hôte via localhost) :
http://localhost:8000Vous devez voir la page d’accueil « Moodle Dev ». Cliquez sur Log in (en haut à droite) et connectez-vous avec :
- Username :
admin - Password :
test
Au premier login, Moodle peut vous demander de compléter le profil administrateur et vous présente le tableau de bord d’administration. Félicitations : vous avez un Moodle 5.2 de développement complet et fonctionnel.
Récapitulatif express des sept étapes (le « quick start » officiel, celui du README de moodle-docker) :
# 0. Variables (persistées dans ~/.bashrc)
export MOODLE_DOCKER_WWWROOT=~/moodle
export MOODLE_DOCKER_DB=pgsql
# 1. Les deux clones
git clone https://github.com/moodlehq/moodle-docker.git ~/moodle-docker
git clone -b MOODLE_502_STABLE https://github.com/moodle/moodle.git "$MOODLE_DOCKER_WWWROOT"
# 2. La config
cp ~/moodle-docker/config.docker-template.php "$MOODLE_DOCKER_WWWROOT/config.php"
# 3. Démarrage
cd ~/moodle-docker
bin/moodle-docker-compose up -d
bin/moodle-docker-wait-for-db
# 4. Installation de la DB
bin/moodle-docker-compose exec webserver php public/admin/cli/install_database.php \
--agree-license --fullname="Moodle Dev" --shortname="moodle_dev" \
--summary="Site de dev" --adminpass="test" --adminemail="admin@example.com"
# 5. → http://localhost:8000 (admin / test)4. Vérifications post-installation
4.1 docker ps annoté
Prenez l’habitude de vérifier l’état de la flotte :
cd ~/moodle-docker
bin/moodle-docker-compose psVous devriez voir quelque chose comme (noms abrégés — le préfixe dépend du nom du dossier ou de COMPOSE_PROJECT_NAME) :
NAME IMAGE STATUS PORTS
moodle-docker-webserver-1 moodlehq/moodle-php-apache:8.3 Up 127.0.0.1:8000->80/tcp
moodle-docker-db-1 postgres:16 Up 5432/tcp
moodle-docker-mailpit-1 axllent/mailpit Up 1025/tcp, 8025/tcp
moodle-docker-selenium-1 selenium/standalone-firefox:... Up 4444/tcp
moodle-docker-exttests-1 moodlehq/moodle-exttests Up 80/tcpLecture ligne par ligne :
- webserver : Apache + PHP 8.3, seul conteneur publié vers l’hôte (
127.0.0.1:8000). Votre code y est monté sur/var/www/html. - db : PostgreSQL 16. Son port 5432 n’est pas publié par défaut — seule la communication interne au réseau Compose est possible (le webserver le joint via le hostname
db). Nous verrons en section 9 comment l’exposer pour un client SQL. - mailpit : écoute en SMTP sur 1025 (c’est là que Moodle « envoie » ses mails) et sert son interface web sur 8025, reverse-proxiée par le webserver sous
/_/mail. - selenium : le navigateur télécommandé pour Behat, joignable en interne sur 4444 (protocole WebDriver).
- exttests : un mini serveur de fixtures pour les tests qui simulent des appels à des services externes (téléchargement de fichiers distants, dépôts, etc.).
4.2 Les logs
Pour voir ce qui se passe (erreurs PHP, requêtes Apache, démarrage de PostgreSQL) :
# Tous les services, en continu
bin/moodle-docker-compose logs -f
# Un seul service
bin/moodle-docker-compose logs -f webserver
# Les 100 dernières lignes de la DB
bin/moodle-docker-compose logs --tail=100 dbLes erreurs PHP de Moodle sortent sur les logs Apache du conteneur webserver : c’est le premier endroit où regarder quand une page blanche ou une erreur 500 apparaît.
💡 Pour un dev React :
logs -f webserverest votre nouvelle consolenext dev. En complément, sachez que Moodle a un « mode développeur » interne (debugging àDEVELOPER, affichage des erreurs à l’écran) que le template docker active déjà en grande partie ; nous consacrerons une section entière aux outils de debug (dont Xdebug, qui s’ajoute via unlocal.yml, section 9).
4.3 Un shell dans le conteneur
Pour explorer l’environnement d’exécution :
bin/moodle-docker-compose exec webserver bash
# Vous êtes maintenant DANS le conteneur :
php -v # PHP 8.3.x
ls /var/www/html # votre code Moodle
ls /var/www/moodledata # les fichiers de données (uploads, caches, sessions)
exitNotez la séparation fondamentale de Moodle : le code (/var/www/html, monté depuis votre ~/moodle) et le moodledata (/var/www/moodledata, un volume Docker contenant fichiers déposés, caches, sessions). Le moodledata ne doit jamais être servi par le web ni vivre dans le dépôt Git.
5. Comptes et données de test
Un Moodle vide, c’est un peu triste : pas de cours, pas d’étudiants, rien à cliquer. Moodle embarque des outils de génération de données spectaculairement pratiques.
5.1 Générer un cours de test complet
L’outil maketestcourse.php crée un cours entier — sections, activités, fichiers, et utilisateurs inscrits — en une commande :
bin/moodle-docker-compose exec webserver php public/admin/tool/generator/cli/maketestcourse.php \
--shortname="TEST_S" \
--size=SLe paramètre --size accepte six tailles, de XS à XL :
| Taille | Ordre de grandeur | Temps de génération | Usage typique |
|---|---|---|---|
XS | ~10 étudiants, quelques activités | secondes | smoke test |
S | ~100 étudiants | < 1 min | dev quotidien |
M | ~1 000 étudiants | quelques minutes | test réaliste |
L | ~10 000 étudiants | long | test de charge léger |
XL | ~50 000 étudiants, gros fichiers | très long, plusieurs Go | test de performance sérieux |
⚠️ Piège : ne lancez pas un
XL« pour voir » sur votre laptop : la génération peut prendre des heures et remplir plusieurs gigaoctets de base et de moodledata.SouMsuffisent largement pour 99 % du travail de développement. Et rappelez-vous que tout cela vit dans des volumes Docker : undown(section 8) effacera tout de toute façon.
Il existe aussi maketestsite.php, qui génère un site entier (de nombreux cours, avec la même échelle XS→XL) — utile pour tester des pages d’accueil, des recherches globales, des rapports :
bin/moodle-docker-compose exec webserver php public/admin/tool/generator/cli/maketestsite.php \
--size=SCe dernier exige d’être lancé sur un site de dev (il refuse de tourner si le site ne semble pas être un environnement de test, par prudence — un flag --bypasscheck existe mais réfléchissez avant).
Les utilisateurs générés ont des identifiants prévisibles du type tool_generator_000001, mot de passe commun ; l’outil affiche les détails en fin de génération. Pratique pour se connecter « en tant qu’étudiant » et voir le cours depuis l’autre côté.
5.2 Créer des utilisateurs à la main
Pour des comptes nominatifs (par exemple un enseignant prof et un étudiant etudiant que vous utiliserez dans toutes vos démos), deux voies :
Via l’interface web (le plus simple au début) : connecté en admin, Site administration → Users → Add a new user. Remplissez username, prénom, nom, e-mail (fictif, Mailpit interceptera), mot de passe. Puis inscrivez l’utilisateur dans un cours avec un rôle (Participants → Enrol users dans le cours).
Via la CLI PHP interactive, pour les scripteurs :
bin/moodle-docker-compose exec webserver php -r '
define("CLI_SCRIPT", true);
require("/var/www/html/config.php");
require_once($CFG->dirroot . "/user/lib.php");
$u = new stdClass();
$u->username = "etudiant";
$u->firstname = "Élise";
$u->lastname = "Tudiant";
$u->email = "etudiant@example.com";
$u->auth = "manual";
$u->confirmed = 1;
$u->mnethostid = 1;
$u->password = "Test1234!";
user_create_user($u);
echo "OK\n";
'Ne vous inquiétez pas si ce code paraît cryptique : la structure d’un script CLI Moodle (CLI_SCRIPT, config.php, API internes) sera expliquée en détail dans la partie « développement ». Retenez simplement que tout ce que fait l’interface web est scriptable.
Enfin, le dossier public/admin/cli/ regorge d’outils prêts à l’emploi que vous utiliserez souvent :
# Réinitialiser un mot de passe (interactif)
bin/moodle-docker-compose exec webserver php public/admin/cli/reset_password.php
# Vider tous les caches (le "rm -rf .next" de Moodle)
bin/moodle-docker-compose exec webserver php public/admin/cli/purge_caches.php
# Basculer le site en mode maintenance
bin/moodle-docker-compose exec webserver php public/admin/cli/maintenance.php --enable
# Exécuter le cron (tâches planifiées) manuellement
bin/moodle-docker-compose exec webserver php public/admin/cli/cron.php💡 Pour un dev React :
purge_caches.phpva devenir un réflexe aussi ancré que supprimer.next/quand quelque chose semble « bloqué ». Moodle met agressivement en cache les définitions de plugins, les chaînes de langue, les templates Mustache compilés… Quand une modification de code ne « prend » pas, purgez les caches avant de chercher plus loin.
6. Mailpit : intercepter les e-mails
6.1 Le problème que ça résout
Moodle envoie beaucoup d’e-mails : confirmations d’inscription, réinitialisations de mot de passe, notifications de forums, rappels de devoirs… En développement, vous voulez trois garanties : (1) ne jamais envoyer un vrai e-mail à une vraie adresse par accident, (2) pouvoir consulter ce qui aurait été envoyé, (3) ne rien configurer.
C’est le rôle d’un mail catcher : un faux serveur SMTP qui accepte tout et n’envoie rien, doublé d’une interface web pour lire les messages capturés. moodle-docker embarque Mailpit (successeur de MailHog, l’outil historique que le projet utilisait auparavant et que vous verrez encore mentionné dans d’anciens tutoriels — MailHog n’étant plus maintenu, moodle-docker a migré vers Mailpit, plus moderne et activement développé).
La configuration est déjà faite : le config.docker-template.php pointe le SMTP de Moodle vers le conteneur mailpit. Vous n’avez rien à toucher.
6.2 Démonstration : réinitialisation de mot de passe
- Ouvrez une fenêtre de navigation privée sur
http://localhost:8000/login/index.php. - Cliquez sur « Lost password? » (mot de passe oublié).
- Saisissez l’adresse d’un utilisateur existant, par exemple
etudiant@example.comcréé en section 5.2, et validez. - Ouvrez l’interface Mailpit :
http://localhost:8000/_/mailLe message « Password reset request » est là, avec son lien cliquable, ses en-têtes complets, sa version HTML et texte brut. Vous pouvez suivre le lien de réinitialisation et dérouler le parcours complet — sans qu’aucun octet n’ait quitté votre machine.
💡 Pour un dev React : Mailpit joue le rôle de l’onglet « preview » de React Email ou du mode sandbox de Resend/Mailtrap : un exutoire local pour tout le trafic SMTP. Bonus appréciable : Mailpit sait afficher le rendu HTML et la source MIME brute, ce qui est précieux quand vous personnaliserez les templates d’e-mails de Moodle.
⚠️ Piège : l’URL est bien
/_/mailsur le port du webserver (8000), pas un port dédié : le conteneur web reverse-proxie l’interface de Mailpit. Si vous cherchez un port 8025 publié sur l’hôte, vous ne le trouverez pas — c’est normal.
7. Behat, Selenium et PHPUnit
Un des super-pouvoirs de moodle-docker : les deux frameworks de test de Moodle fonctionnent immédiatement, sans configuration. Sur une installation manuelle, faire marcher Behat + Selenium est notoirement pénible ; ici, tout est pré-câblé.
7.1 Behat : les tests fonctionnels pilotés par le navigateur
Behat exécute des scénarios rédigés en Gherkin (« Given I log in as “admin” / When I follow “My courses” / Then I should see… ») dans un vrai navigateur, piloté via Selenium. Moodle en compte des milliers.
Initialisation (à refaire après chaque grosse mise à jour du code) :
bin/moodle-docker-compose exec webserver php public/admin/tool/behat/cli/init.phpCe script crée un site Moodle parallèle dédié aux tests (sa propre base préfixée, son propre dataroot behatdata) : vos données de dev ne sont jamais touchées par les tests. L’initialisation prend plusieurs minutes la première fois.
Lancer un test d’exemple — par exemple une feature du système d’authentification :
bin/moodle-docker-compose exec webserver \
vendor/bin/behat --config /var/www/behatdata/behatrun/behat/behat.yml \
--tags=@auth_manualVous verrez défiler les étapes des scénarios, avec un verdict vert/rouge par étape. Le chemin exact du behat.yml est affiché à la fin de l’init.php — copiez-le depuis là.
Regarder le navigateur travailler (VNC) : par défaut, Selenium tourne « sans tête visible » dans son conteneur. Pour voir Firefox cliquer tout seul — hypnotique et très utile pour déboguer un scénario — exposez le port VNC :
# Dans ~/.bashrc ou la session courante :
export MOODLE_DOCKER_SELENIUM_VNC_PORT=5900
# Recréer les conteneurs pour prendre en compte la variable :
cd ~/moodle-docker
bin/moodle-docker-compose up -dPuis connectez une visionneuse VNC (par exemple TightVNC ou RealVNC Viewer sous Windows) sur 127.0.0.1:5900, mot de passe secret. Relancez un test Behat : vous voyez le navigateur en direct.
Changer de navigateur : Firefox est le défaut ; Chrome se demande par variable, et vous pouvez épingler une version précise via un tag d’image :
export MOODLE_DOCKER_BROWSER=chrome
# ou, version épinglée :
export MOODLE_DOCKER_BROWSER=firefox:135
bin/moodle-docker-compose up -d # recréation nécessaire⚠️ Piège : les variables
MOODLE_DOCKER_*ne sont lues qu’à la (re)création des conteneurs. Modifier une variable puis relancer un test sansup -d(voire sansdownpour les changements structurels comme la DB, cf. section 8) n’a aucun effet. Quand « la variable ne marche pas », c’est presque toujours ça.
7.2 PHPUnit : les tests unitaires
Même logique en deux temps, initialisation puis exécution :
# Initialisation (crée la base et le dataroot dédiés aux tests unitaires)
bin/moodle-docker-compose exec webserver php public/admin/tool/phpunit/cli/init.php
# Lancer un fichier de tests précis :
bin/moodle-docker-compose exec webserver \
vendor/bin/phpunit --filter auth_manual public/auth/manual/tests/manual_test.php
# Ou toute la suite d'un composant :
bin/moodle-docker-compose exec webserver \
vendor/bin/phpunit --testsuite core_favourites_testsuite⚠️ Piège : ne lancez jamais
vendor/bin/phpunitsans argument sur le dépôt Moodle complet : la suite intégrale représente des dizaines de milliers de tests et plusieurs heures. Ciblez toujours un fichier, un filtre ou une testsuite. En pratique, quand vous développerez un plugin, vous ne lancerez que les tests de votre plugin.
📚 Aller plus loin : les pages « Behat » et « PHPUnit » de moodledev.io (moodledev.io/general/development/tools) documentent tags, profils, options de parallélisation et rédaction de vos propres tests. Nous y consacrerons un chapitre complet dans la partie « qualité ».
8. Cycle de vie de l’environnement
C’est ici que se joue votre confort quotidien — et que se cache le piège le plus destructeur de tout l’outil.
8.1 stop / start : le quotidien
En fin de journée, ou pour libérer de la RAM :
cd ~/moodle-docker
bin/moodle-docker-compose stopLes conteneurs s’arrêtent, toutes les données sont conservées : base de données, moodledata, sites Behat/PHPUnit initialisés. Le lendemain :
bin/moodle-docker-compose startet vous retrouvez votre site exactement dans l’état où vous l’avez laissé, en quelques secondes. C’est le couple de commandes de votre routine.
8.2 down : le reset nucléaire
bin/moodle-docker-compose down⚠️ Piège (le plus important du chapitre) :
downne se contente pas d’arrêter les conteneurs : il les supprime, ainsi que les volumes associés — donc la base de données entière et le moodledata. Vos cours, utilisateurs, réglages : tout disparaît. Seul survit ce qui est sur votre disque : le code Moodle etconfig.php. Le réflexe Docker habituel « down le soir, up le matin » est ici une erreur : au quotidien c’eststop/start;downest réservé au reset volontaire ou aux changements de configuration structurels.
down est en revanche l’outil parfait pour repartir de zéro proprement :
bin/moodle-docker-compose down
bin/moodle-docker-compose up -d
bin/moodle-docker-wait-for-db
bin/moodle-docker-compose exec webserver php public/admin/cli/install_database.php \
--agree-license --fullname="Moodle Dev" --shortname="moodle_dev" \
--summary="Site de dev" --adminpass="test" --adminemail="admin@example.com"Trois commandes, cinq minutes, et vous avez un site neuf. Cette jetabilité est une fonctionnalité : n’ayez jamais peur de casser votre site de dev, il se reconstruit plus vite qu’il ne se répare.
8.3 Mettre à jour le code Moodle
La branche MOODLE_502_STABLE reçoit régulièrement des correctifs (versions 5.2.1, 5.2.2…). Pour suivre :
cd ~/moodle
git pull
cd ~/moodle-docker
bin/moodle-docker-compose exec webserver php public/admin/cli/upgrade.php --non-interactiveupgrade.php applique les éventuelles migrations de schéma et purge les caches. Après une mise à jour notable, ré-initialisez Behat/PHPUnit (section 7) si vous les utilisez, car leurs sites parallèles doivent suivre la version du code.
8.4 Changer de version PHP ou de base de données
Ces changements modifient les images utilisées : il faut détruire et recréer les conteneurs — donc down obligatoire (et perte des données, voir 8.2) :
cd ~/moodle-docker
bin/moodle-docker-compose down
export MOODLE_DOCKER_PHP_VERSION=8.4 # tester Moodle 5.2 sous PHP 8.4
export MOODLE_DOCKER_DB=mariadb # et/ou changer de moteur de DB
bin/moodle-docker-compose up -d
bin/moodle-docker-wait-for-db
# ... puis réinstaller la base (install_database.php)C’est précisément le scénario où moodle-docker brille pour un développeur de plugins : valider son code sous PHP 8.3 et 8.4, sous PostgreSQL et MariaDB, ne coûte que quelques minutes par combinaison — exactement ce que fait la CI de Moodle.
8.5 Plusieurs instances en parallèle
Besoin d’un Moodle 5.2 et d’un Moodle « main » côte à côte ? Docker Compose isole les projets par nom via COMPOSE_PROJECT_NAME. Combinez-le avec des chemins et ports distincts :
# Terminal / profil "instance A"
export COMPOSE_PROJECT_NAME=moodle52
export MOODLE_DOCKER_WWWROOT=~/moodle-52
export MOODLE_DOCKER_WEB_PORT=127.0.0.1:8000
export MOODLE_DOCKER_DB=pgsql
# Terminal / profil "instance B"
export COMPOSE_PROJECT_NAME=moodlemain
export MOODLE_DOCKER_WWWROOT=~/moodle-main
export MOODLE_DOCKER_WEB_PORT=127.0.0.1:8001
export MOODLE_DOCKER_DB=pgsqlChaque projet a ses propres conteneurs, réseaux et volumes ; bin/moodle-docker-compose agit toujours sur le projet désigné par les variables de la session courante. Un petit script à sourcer par instance (source ~/env-moodle52.sh) évite les mélanges.
⚠️ Piège : si vous oubliez de changer
MOODLE_DOCKER_WEB_PORT, la seconde instance échouera au démarrage (port déjà pris) — c’est le cas bénin. Le cas vicieux, c’est d’oublierCOMPOSE_PROJECT_NAME: Compose croira que vous reconfigurez le même projet et recréera les conteneurs de l’instance A avec le code de l’instance B. Vérifiez toujours avecbin/moodle-docker-compose psque vous parlez au bon projet.
9. Personnalisation avec local.yml
moodle-docker prévoit un point d’extension officiel : si un fichier local.yml existe à la racine de votre clone ~/moodle-docker, il est automatiquement ajouté à la pile des fichiers Compose, en dernier — il peut donc surcharger ou compléter tout le reste. C’est le mécanisme standard d’override de Docker Compose, sans avoir à toucher aux fichiers du dépôt (qui resteraient sinon en conflit à chaque git pull).
💡 Pour un dev React :
local.ymlest à moodle-docker ce quedocker-compose.override.ymlest à un projet Compose classique, ou ce qu’unnext.config.localserait s’il existait : vos ajouts personnels, non versionnés dans le projet amont, fusionnés par-dessus la configuration de base.
9.1 Exemple 1 — Exposer le port PostgreSQL pour DBeaver/TablePlus
Vous voulez inspecter la base depuis un client SQL graphique installé sous Windows ? Le plus simple est la variable dédiée :
export MOODLE_DOCKER_DB_PORT=5432
bin/moodle-docker-compose down # changement structurel → down puis up
bin/moodle-docker-compose up -d(La variable accepte aussi la forme ip:port ; un simple 5432 publie sur 127.0.0.1:5432.) Configurez ensuite DBeaver ou TablePlus côté Windows :
- Hôte :
localhost, port :5432 - Base :
moodle, utilisateur :moodle, mot de passe :m@0dl3ing
(Ces identifiants par défaut sont visibles dans les fichiers db.*.yml du dépôt moodle-docker.) Explorer les tables mdl_user, mdl_course, mdl_course_modules au fil de vos lectures des prochains chapitres est un excellent accélérateur de compréhension du modèle de données.
9.2 Exemple 2 — Ajouter Redis
Moodle sait utiliser Redis comme magasin de cache et de sessions (nous le verrons au chapitre performances). Pour l’avoir sous la main en dev, créez ~/moodle-docker/local.yml :
services:
redis:
image: redis:7Puis :
bin/moodle-docker-compose up -dLe conteneur redis rejoint le réseau du projet ; depuis Moodle, il sera joignable sous le hostname redis (port 6379) — configurable ensuite dans Site administration → Plugins → Caching.
9.3 Exemple 3 — Monter un plugin en développement
Scénario central pour la suite de cette documentation : votre plugin vit dans son propre dépôt Git (bonne pratique absolue — on ne développe pas un plugin dans une copie du dépôt Moodle), et vous voulez qu’il apparaisse au bon endroit de l’arborescence Moodle. Deux approches :
Approche volume Compose (local.yml) :
services:
webserver:
volumes:
- "/home/alex/dev/moodle-local_hello:/var/www/html/public/local/hello"Approche lien symbolique (souvent plus simple, tout se passe côté fichiers) :
ln -s ~/dev/moodle-local_hello ~/moodle/public/local/helloDans les deux cas, le code du plugin reste dans son dépôt dédié, avec son propre historique Git, tout en étant vu par Moodle à l’emplacement attendu (public/local/hello pour un plugin de type « local » nommé hello — la taxonomie des types de plugins arrive dans la partie développement).
⚠️ Piège : notez le
public/dans le chemin cible. Avant Moodle 5.1, un plugin local se montait sur/var/www/html/local/hello; depuis la restructuration, c’est/var/www/html/public/local/hello. Les tutoriels et leslocal.ymld’avant 2025 sont tous à ajuster sur ce point.
📚 Aller plus loin : le README de moodle-docker documente d’autres usages de
local.ymlet de variables avancées : ajout de Xdebug (avec un guide dédié dans le wiki du projet), conteneur pour l’app mobile (MOODLE_DOCKER_APP_PATH/MOODLE_DOCKER_APP_VERSION— un conteneur Ionic sert l’app sur un port dédié, pour tester vos plugins face à l’app officielle), configuration de MLBackend pour les fonctions d’analytique, etc.
10. Spécificités Windows / WSL2
Regroupons ici tout ce qui est propre à votre plateforme, au-delà de la règle d’or « code dans WSL2 » déjà établie.
10.1 Éditer le code : VS Code Remote-WSL
N’éditez pas les fichiers via le partage réseau \\wsl$\... avec un éditeur Windows classique : c’est lent et source de problèmes de fins de ligne. La bonne pratique est l’extension WSL de VS Code (ms-vscode-remote.remote-wsl) :
# Depuis le terminal Ubuntu, dans le dossier du code :
cd ~/moodle
code .VS Code s’ouvre côté Windows, mais son « serveur » tourne dans Ubuntu : le terminal intégré est un vrai bash WSL2, les extensions (Intelephense/PHP, ESLint…) s’exécutent côté Linux, Git opère nativement sur le système de fichiers Linux. Vous avez le confort de Windows et les performances de Linux.
Quelques extensions utiles pour Moodle : PHP Intelephense (ou l’extension PHP de DEVSENSE), Moodle - Snippets & Autocomplete, Gherkin/Cucumber pour les fichiers .feature de Behat, EditorConfig (Moodle fournit un .editorconfig).
10.2 Fins de ligne : CRLF vs LF
Le code Moodle utilise des fins de ligne Unix (LF). Si Git est configuré côté Windows avec core.autocrlf=true et que vous clonez/committez depuis Windows, vous pouvez introduire des CRLF qui cassent les scripts shell et polluent les diffs. Dans WSL2, le défaut est sain, mais verrouillez-le :
git config --global core.autocrlf inputEt dans VS Code, vérifiez que la barre d’état indique LF sur les fichiers du projet (l’.editorconfig de Moodle s’en charge si l’extension EditorConfig est installée).
⚠️ Piège : le symptôme classique d’un problème CRLF est un script qui échoue avec
/usr/bin/env: 'php\r': No such file or directory— ce\rtraître à la fin est un retour chariot Windows. Si vous voyez ça, un fichier a été enregistré en CRLF.
10.3 Permissions et www-data
Dans le conteneur, Apache tourne sous l’utilisateur www-data. Votre code, monté depuis WSL2, appartient à votre utilisateur Linux. Pour la simple lecture du code, aucun problème. Les écritures de Moodle (uploads, caches) vont dans le moodledata, qui est un volume Docker géré avec les bonnes permissions — pas dans votre code. Vous ne devriez donc quasiment jamais rencontrer de souci de permissions avec moodle-docker.
Le cas résiduel : si un outil (installeur de plugin via l’interface web, par exemple) tente d’écrire dans le code, il échouera car www-data n’a pas les droits sur vos fichiers. En dev, c’est en réalité une bonne chose : installez vos plugins par Git/symlink (section 9.3), jamais par l’upload web.
10.4 L’horloge WSL2 après hibernation
Bug bien connu : après une mise en veille prolongée de Windows, l’horloge de la VM WSL2 peut rester « bloquée » dans le passé, parfois de plusieurs heures. Conséquences pour Moodle : sessions qui expirent bizarrement, jetons invalides, caches incohérents, tests Behat qui échouent sur des dates.
Symptôme et correctif :
date # si l'heure affichée est fausse…
sudo hwclock -s # …resynchronise l'horloge de WSL2 sur l'hôteOu plus radical, depuis PowerShell :
wsl --shutdown
# puis rouvrir un terminal Ubuntu et relancer Docker Desktop si besoinLes versions récentes de WSL2 ont largement corrigé le problème, mais gardez ce réflexe dans un coin de la tête : « heure bizarre dans les logs → hwclock -s ».
10.5 RAM et .wslconfig
Docker Desktop + WSL2 + Moodle + Selenium, c’est gourmand. Si votre machine a 16 Go ou moins, plafonnez la VM WSL2 en créant C:\Users\Alexl\.wslconfig :
[wsl2]
memory=8GB
processors=4Puis wsl --shutdown (PowerShell) pour appliquer. Sans plafond, le cache disque de Linux peut faire gonfler vmmem jusqu’à consommer l’essentiel de votre RAM.
📚 Aller plus loin : le fichier
.wslconfigaccepte de nombreux réglages (swap, réseau miroir,autoMemoryReclaimen versions récentes) documentés sur learn.microsoft.com/windows/wsl/wsl-config.
11. Alternative rapide : l’image bitnami/moodle
Avant de conclure, un mot sur une alternative que vous croiserez inévitablement dans vos recherches : les images Moodle « clés en main », dont la plus connue est celle de Bitnami. Il est important de comprendre à quoi elles servent — et pourquoi elles ne remplacent pas moodle-docker pour développer.
11.1 Le cas d’usage : une démo en cinq minutes
L’image bitnami/moodle embarque Moodle pré-installé dans l’image : vous la lancez avec une base MariaDB, et quelques minutes plus tard un Moodle fonctionnel répond, installation web comprise. Idéal pour : montrer Moodle à un client, tester une fonctionnalité utilisateur, évaluer l’outil sans rien connaître à son installation.
Un docker-compose.yml minimal complet (à placer dans un dossier vide, puis docker compose up -d) :
# docker-compose.yml — démo Moodle jetable (PAS pour le développement)
services:
mariadb:
image: bitnami/mariadb:latest
environment:
- ALLOW_EMPTY_PASSWORD=yes # démo uniquement !
- MARIADB_USER=bn_moodle
- MARIADB_DATABASE=bitnami_moodle
- MARIADB_CHARACTER_SET=utf8mb4
- MARIADB_COLLATE=utf8mb4_unicode_ci
volumes:
- mariadb_data:/bitnami/mariadb
moodle:
image: bitnami/moodle:latest
ports:
- "127.0.0.1:8080:8080"
environment:
- MOODLE_DATABASE_HOST=mariadb
- MOODLE_DATABASE_PORT_NUMBER=3306
- MOODLE_DATABASE_USER=bn_moodle
- MOODLE_DATABASE_NAME=bitnami_moodle
- MOODLE_USERNAME=admin
- MOODLE_PASSWORD=Admin1234!
- MOODLE_EMAIL=admin@example.com
- ALLOW_EMPTY_PASSWORD=yes # démo uniquement !
volumes:
- moodle_data:/bitnami/moodle
- moodledata_data:/bitnami/moodledata
depends_on:
- mariadb
volumes:
mariadb_data:
moodle_data:
moodledata_data:Lancement, puis patience le temps de l’auto-installation (suivez docker compose logs -f moodle) ; le site répond ensuite sur http://localhost:8080 avec le compte admin / Admin1234!.
11.2 Pourquoi ce n’est PAS un environnement de développement
- Le code est enfoui dans l’image. Vous ne l’avez pas cloné, il n’est pas sous Git, il vit dans un volume géré par les scripts Bitnami. Modifier un fichier du cœur ou développer un plugin y est acrobatique et fragile — c’est l’exact opposé du modèle « mon code sur mon disque, monté dans le conteneur ».
- Pas d’outillage de dev. Ni Behat, ni PHPUnit configurés, ni Selenium, ni Mailpit : les e-mails partent dans le vide (ou pas du tout), les tests sont impossibles sans un travail de configuration qui annule tout le gain de temps initial.
- Le cycle de versions vous échappe. Vous êtes tributaire du rythme et des choix de packaging de Bitnami : impossible de tester la branche
mainde Moodle, un correctif de sécurité du matin, ou une combinaison PHP/DB précise. - La version de Moodle disponible n’est pas garantie. Suivant le calendrier de Bitnami, la toute dernière version majeure (comme 5.2) peut mettre du temps à apparaître, ou ne pas être proposée dans la variante attendue.
À cela s’ajoute un changement de contexte majeur : en août 2025, Broadcom (propriétaire de Bitnami) a drastiquement restreint son catalogue gratuit. Depuis le 28 août 2025, la plupart des images versionnées ont été déplacées vers le dépôt docker.io/bitnamilegacy (non maintenu, sans mises à jour de sécurité), et le catalogue gratuit docker.io/bitnami ne conserve qu’un sous-ensemble d’applications, uniquement en tag latest, présenté comme destiné au développement ; l’accès complet (historique de versions, images durcies, support) est passé dans l’offre payante « Bitnami Secure Images ». Concrètement : un bitnami/moodle:4.5.3 épinglé peut aujourd’hui échouer au docker pull, et s’appuyer sur latest rend vos environnements non reproductibles. Vérifiez l’état du catalogue au moment où vous lirez ces lignes, car la situation a continué d’évoluer depuis.
⚠️ Piège : ne bâtissez aucun workflow durable (dev, CI, staging) sur les images Bitnami gratuites dans ce contexte. Pour une démo jetable de dix minutes,
latestfait l’affaire ; pour tout le reste, moodle-docker (dev) ou une installation maîtrisée (prod, chapitre dédié) sont les seules options saines.
📚 Aller plus loin : l’annonce officielle des changements Bitnami est documentée dans les issues GitHub bitnami/containers#83267 et bitnami/charts#35164 , et analysée notamment par The New Stack et le blog Docker .
Verdict : bitnami/moodle = démo, moodle-docker = développement. Les deux outils ne jouent pas dans la même catégorie, et maintenant vous savez pourquoi.
12. Tableau récapitulatif des commandes
Toutes les commandes s’exécutent depuis ~/moodle-docker (WSL2), variables MOODLE_DOCKER_WWWROOT et MOODLE_DOCKER_DB définies.
| Action | Commande | Données conservées ? |
|---|---|---|
| Démarrer / créer les conteneurs | bin/moodle-docker-compose up -d | oui (crée si absent) |
| Attendre que la DB soit prête | bin/moodle-docker-wait-for-db | — |
| Installer la base Moodle | bin/moodle-docker-compose exec webserver php public/admin/cli/install_database.php --agree-license --fullname="..." --shortname="..." --adminpass="..." --adminemail="..." | crée les données |
| Pause quotidienne | bin/moodle-docker-compose stop | oui |
| Reprise | bin/moodle-docker-compose start | oui |
| Destruction complète (reset) | bin/moodle-docker-compose down | NON — tout est effacé |
| État des conteneurs | bin/moodle-docker-compose ps | — |
| Logs en continu | bin/moodle-docker-compose logs -f [service] | — |
| Shell dans le conteneur web | bin/moodle-docker-compose exec webserver bash | — |
| Purger les caches Moodle | ... exec webserver php public/admin/cli/purge_caches.php | oui |
| Lancer le cron | ... exec webserver php public/admin/cli/cron.php | oui |
| Mettre à jour Moodle | git pull (dans ~/moodle) puis ... exec webserver php public/admin/cli/upgrade.php --non-interactive | oui |
| Générer un cours de test | ... exec webserver php public/admin/tool/generator/cli/maketestcourse.php --shortname=TEST --size=S | oui |
| Générer un site de test | ... exec webserver php public/admin/tool/generator/cli/maketestsite.php --size=S | oui |
| Initialiser Behat | ... exec webserver php public/admin/tool/behat/cli/init.php | oui |
| Lancer Behat | ... exec webserver vendor/bin/behat --config <behat.yml> --tags=@... | oui |
| Initialiser PHPUnit | ... exec webserver php public/admin/tool/phpunit/cli/init.php | oui |
| Lancer PHPUnit | ... exec webserver vendor/bin/phpunit <chemin/du/test> | oui |
| Interface e-mails (Mailpit) | navigateur → http://localhost:8000/_/mail | — |
| VNC Selenium | export MOODLE_DOCKER_SELENIUM_VNC_PORT=5900 + up -d, viewer sur 127.0.0.1:5900 (mdp secret) | — |
Et les variables d’environnement à connaître par cœur :
| Variable | Obligatoire | Défaut | Exemple |
|---|---|---|---|
MOODLE_DOCKER_WWWROOT | oui | — | ~/moodle |
MOODLE_DOCKER_DB | oui | — | pgsql |
MOODLE_DOCKER_PHP_VERSION | non | 8.3 | 8.4 |
MOODLE_DOCKER_WEB_PORT | non | 127.0.0.1:8000 | 127.0.0.1:8001 |
MOODLE_DOCKER_DB_PORT | non | (non exposé) | 5432 |
MOODLE_DOCKER_BROWSER | non | firefox | chrome, firefox:135 |
MOODLE_DOCKER_SELENIUM_VNC_PORT | non | (désactivé) | 5900 |
MOODLE_DOCKER_APP_PATH / _VERSION | non | (désactivé) | test app mobile |
COMPOSE_PROJECT_NAME | non | nom du dossier | moodle52 |
Récapitulatif
- moodle-docker est le wrapper Docker Compose officiel de Moodle HQ, celui de la CI du projet : webserver Apache+PHP, base de données au choix (pgsql/mariadb/mysql/mssql/oracle), Mailpit, Selenium et exttests. C’est un outil de développement, jamais de production.
- Sur Windows 11 : WSL2 + Docker Desktop (backend WSL2), et le code Moodle impérativement dans le système de fichiers Linux (
~/moodle, jamais/mnt/c) sous peine de performances catastrophiques. Édition via VS Code Remote-WSL. - La mise en place tient en sept étapes : variables (
MOODLE_DOCKER_WWWROOT,MOODLE_DOCKER_DB, persistées dans~/.bashrc), clone de moodle-docker, clone de Moodle surMOODLE_502_STABLE, copie deconfig.docker-template.phpenconfig.php(un config 100 % piloté par variables d’environnement — le.env.localde Moodle),up -d,wait-for-db,install_database.php. - Depuis Moodle 5.1, le code web vit dans
public/: les scripts CLI se lancent enphp public/admin/cli/..., et il faut garder son clone de moodle-docker à jour pour que les images ajustent le DocumentRoot. - Cycle de vie :
stop/startau quotidien (données conservées),down= destruction totale des conteneurs et volumes — c’est aussi le reset propre, et un passage obligé pour changer de version PHP ou de moteur de DB. Plusieurs instances cohabitent viaCOMPOSE_PROJECT_NAME+ ports distincts. - Les e-mails sont interceptés par Mailpit (
http://localhost:8000/_/mail) ; Behat et PHPUnit sont pré-configurés (init.phppuisvendor/bin/behat/vendor/bin/phpunit), avec observation possible du navigateur Selenium en VNC (127.0.0.1:5900, mot de passesecret). local.ymlpermet d’étendre la pile (Redis, montage d’un plugin, Xdebug) etMOODLE_DOCKER_DB_PORTd’ouvrir la base à un client SQL Windows.- L’image bitnami/moodle dépanne pour une démo de cinq minutes mais est inadaptée au développement (code enfoui, pas d’outillage de test, versions non maîtrisées — et catalogue gratuit drastiquement restreint depuis août 2025).
Dans le prochain chapitre
Votre environnement tourne, mais nous l’avons piloté pour l’instant « de l’extérieur ». Dans le chapitre 4.3, nous nous installerons durablement dans le poste de travail du développeur Moodle : configuration fine de VS Code (Intelephense, débogage pas à pas avec Xdebug branché sur les conteneurs, snippets Moodle), prise en main de la CLI Moodle au quotidien (purge_caches, cron, mode maintenance), premiers repères dans l’arborescence du code (public/, lib/, la notion de composant), et le pipeline front de Moodle (Grunt, AMD, Mustache) — tout ce qu’il faut pour passer de « j’ai un Moodle qui tourne » à « je suis outillé pour le modifier ».