<!--
  canonical-url: https://www.avonture.be/fr/blog/docker-joomla
  published:     2023-12-22
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Créer votre site Joomla avec Docker - Partie 1

> Apprenez à mettre en place rapidement votre site Joomla en local avec Docker. Ce guide pas à pas couvre Docker Compose, la configuration de la base de données (MySQL/MariaDB) et le lancement de vos services.

---
![Créer votre site Joomla avec Docker - Partie 1](/img/v2/joomla.webp)

**TL;DR**

Cet article détaille comment mettre en place rapidement un site Joomla en
local avec Docker, en configurant un fichier `compose.yaml` pour orchestrer le
service applicatif et celui de la base de données. Il explique les étapes
essentielles pour assurer la persistance des données via la synchronisation
des volumes, gérer les ports pour plusieurs projets et personnaliser les
connexions à la base. Le tutoriel se termine par une commande CLI en une ligne
pour déployer tout l'environnement en quelques secondes.

Dans cet article, nous allons voir comment utiliser Docker pour installer Joomla sur votre localhost et démarrer un nouveau site **en quelques secondes**.

J'utilise une console Linux *(je fais tourner WSL sur mon ordinateur Windows et j'ai choisi Ubuntu comme distribution)* mais comme Docker fonctionne aussi sous Windows, vous pouvez lancer exactement les mêmes commandes dans une console MS-DOS / PowerShell.

**Quick Jump:** [Deux minutes, un fichier](#two-minutes-one-file-your-joomla-is-running) | [Bonus - une seule ligne de commande](#bonus---install-joomla-with-a-cli-one-liner)

Si vous n'avez pas encore Docker, consultez mon article « [Installer Docker et jouer avec PHP](/blog/install-docker) » pour en savoir plus sur Docker et obtenir un guide d'introduction simple.

**Nous partons du principe, dans cet article, que vous avez Docker et que vous travaillez sous Linux ou avec WSL.**

## Deux minutes, un fichier, et votre Joomla tourne {#two-minutes-one-file-your-joomla-is-running}

Cliquez sur `Generate install script` ci-dessous et copiez/collez le script dans un terminal :

**Project: /tmp/joomla**

**compose.yaml**

```yaml
services:
  joomla:
    image: joomla
    restart: always
    ports:
      - 8080:80
    environment:
      - JOOMLA_DB_HOST=joomladb
      - JOOMLA_DB_PASSWORD=example

  joomladb:
    image: mysql:8.0.13
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=example
```

> **Note:**
>
> Maintenant, lancez simplement 'docker compose up -d' pour démarrer le projet
> puis ouvrez votre navigateur et rendez-vous sur <http://localhost:8080>

Lancez `docker compose up --detach`, attendez le téléchargement des images, puis ouvrez `http://localhost:`8080 :

> Screenshot — http\://localhost:8080
>
> ![Installateur Joomla](./images/joomla_installation_screen.webp)

Répondez aux questions de l'installateur et, quelques secondes plus tard, vous voilà ici :

> Screenshot — http\://localhost:8080/aministrator/index.php
>
> ![Tableau de bord d'administration Joomla](./images/admin_dashboard.webp)

Un site Joomla complet, sur votre machine, avec une base de données — et pas un seul fichier de Joomla ou de MySQL installé sur votre disque.

## Que vient-il de se passer {#what-just-happened}

Cette unique commande a demandé à Docker de lire le fichier `compose.yaml` et, à partir de là :

1. un réseau `joomla_default` est créé,
2. le container `joomla-joomladb-1` est créé (c'est votre serveur de base de données) et
3. le container `joomla-joomla-1` est créé lui aussi (c'est votre service Joomla).

Les deux containers partagent le réseau, c'est comme ça que Joomla peut joindre la base de données par son nom de service. La suite de cet article explique ce fichier ligne par ligne, puis va beaucoup plus loin : persister votre site sur le disque, lancer des commandes CLI, changer de port, passer à PostgreSQL ou MariaDB.

## Avant de commencer {#before-starting}

**Comme vous le savez, pour faire tourner un CMS comme Joomla, il nous faut trois choses + 1 :**

1. Il nous faut un serveur web comme **Apache** ou **nginx**

2. Il nous faut un service de base de données comme **MySQL**, **MariaDB** ou **PostgreSQL** ou toute autre base supportée et

3. Il nous faut **PHP** et

4. Bien sûr, il nous faut **Joomla**

En termes Docker : il nous faut trois services.

## Docker compose {#docker-compose}

Quand vous avez besoin de plusieurs services (Apache doit pouvoir communiquer avec PHP et PHP doit pouvoir demander des données à MySQL), vous devez configurer un fichier particulier appelé `compose.yaml`. Ce fichier doit être placé à la racine du projet et va définir la liste des services nécessaires ainsi que la manière dont ils collaborent.

Vous trouverez un exemple de fichier `compose.yaml` sur la page de description de l'image Joomla : <https://hub.docker.com/_/joomla> *cherchez `docker-compose` sur cette page.*

> **L'image Docker Joomla est construite sur PHP et Apache:**
>
> C'est sûrement trop technique à ce stade mais si vous cliquez sur le lien
> <https://github.com/joomla-docker/docker-joomla/blob/master/6.1/php8.4/apache/Dockerfile>,
> vous verrez que l'image Docker de Joomla 6.1 est construite sur une image
> `php:8.4-apache`. Autrement dit, avec cette image vous obtenez PHP, Apache et
> Joomla, le tout dans une seule image.

## Télécharger les images {#download-images}

Revenons au script de génération du début de cet article et regardons ce qu'il a réellement fait. Pour que ce soit le plus clair possible, voici le contenu de mon dossier temporaire une fois le script exécuté :

```bash
cd /tmp/joomla

$ ls -alh
total 12K
drwxr-xr-x 2 christophe christophe 4.0K Jan 4 15:31 .
drwxrwxrwt 12 root root 4.0K Jan 4 15:31 ..
-rw-r--r-- 1 christophe christophe 279 Jan 4 15:31 compose.yaml
```

Donc je n'ai qu'un seul fichier, et c'est le fichier `compose.yaml` fraîchement créé.

> **`docker compose up --detach` est l'une des commandes les plus importantes à connaître. Elle demande à Docker de traiter le fichier `compose.yaml` et de lancer les services. En bref : elle démarre votre site.:**

Docker va commencer à télécharger `joomla` et `joomladb`, les deux services mentionnés dans le fichier `compose.yaml`.

**compose.yaml**

```yaml
services:
  // highlight-next-line
  joomla:
    [...]
  // highlight-next-line
  joomladb:
    [...]
```

Vous obtiendrez quelque chose comme ceci, patientez le temps que tout soit téléchargé.

```bash
$ docker compose up --detach

[+] Running 16/35
⠹ joomladb 12 layers [⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀] 0B/0B Pulling 19.3s
⠧ 177e7ef0df69 Waiting 15.8s
⠧ cac25352c4c8 Waiting 15.8s
⠧ 8585afabb40a Waiting 15.8s
[...]
⠹ joomla 21 layers [⣿⣿⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣿⣿⣿⣿⣀⠀⠀] 94.59MB/155.9MB Pulling 19.3s
✔ 578acb154839 Pull complete 11.3s
✔ c053f6f43c12 Pull complete 11.9s
⠋ 65cebbf4d847 Downloading [==============> ] 68.41MB/104.4MB 16.1s
✔ 34045bc93960 Download complete 1.0s
[...]
```

À la fin, une fois les images téléchargées, la console affichera quelque chose comme ceci :

```bash
$ docker compose up --detach

[+] Running 35/35
✔ joomladb 12 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 84.9s
✔ 177e7ef0df69 Pull complete 26.9s
✔ cac25352c4c8 Pull complete 27.5s
✔ 8585afabb40a Pull complete 28.2s
[...]
✔ joomla 21 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 146.4s
✔ 578acb154839 Pull complete 11.3s
✔ c053f6f43c12 Pull complete 11.9s
✔ 65cebbf4d847 Pull complete 31.2s
[...]
[+] Running 3/3
✔ Network joomla_default Created 0.3s
✔ Container joomla-joomladb-1 Started 52.9s
✔ Container joomla-joomla-1 Started 38.8s
```

Les deux images ont été téléchargées, et le réseau ainsi que les deux containers cités plus haut ont été créés.

À ce stade, votre site est déjà en cours d'installation. Rendez-vous sur l'URL `http://127.0.0.1:`8080 pour le voir (veillez à utiliser le protocole `http` et pas `https`).

> **Pas encore prêt:**
>
> Vous obtiendrez peut-être une page d'erreur `ERR_EMPTY_RESPONSE` ; c'est
> parce que, par exemple, MySQL n'est pas encore complètement chargé et Joomla
> doit l'attendre avant de pouvoir afficher la page d'installation. Dans ce cas,
> patientez encore un peu... ou lisez la suite de cet article.

> **Résolvez-le en ajoutant une condition depends\_on:**
>
> Joomla peut donc être prêt avant la base de données, et ce n'est pas bon. En effet, Joomla doit pouvoir créer sa base, ajouter des tables et des enregistrements mais si MySQL n'est pas encore prêt, nous aurons un problème.
>
> La solution proposée par Docker est la notion de `healthcheck`. Nous devons définir comment Docker peut *savoir* que MySQL est *healthy*. Ensuite, nous demanderons à Joomla d'attendre que le layer base de données soit *healthy*.
>
> **compose.yaml**
>
> ```yaml
> services:
>   // highlight-next-line
>   joomla:
>     [...]
>     // highlight-next-line
>     depends_on:
>       // highlight-next-line
>       joomladb:
>         // highlight-next-line
>         condition: service_healthy
>
>   // highlight-next-line
>   joomladb:
>     [...]
>     // highlight-next-line
>     healthcheck:
>       // highlight-next-line
>       test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
>       // highlight-next-line
>       timeout: 20s
>       // highlight-next-line
>       retries: 10
> ```

### Pourquoi des noms joomla-joomlaxxx {#why-joomla-joomlaxxx-names}

Nous n'avons pas donné de nom à votre projet, nous avons juste créé un fichier `compose.yaml` dans votre dossier `/tmp/joomla`. Docker a donc nommé votre projet en utilisant le nom du dossier (`joomla`) concaténé au nom du service (regardez le fichier `compose.yaml` : nous avons deux services, un appelé `joomladb` et un appelé `joomla`). Voilà pourquoi...

Introduisons une petite modification, facultative : nous allons donner un nom à votre projet Docker et à vos containers. Éditez le fichier `compose.yaml` et ajoutez une ligne avec `name: xxxx` où `xxxx` est le nom de votre choix. Faites de même mais avec `container_name` cette fois pour les deux services ; par exemple :

**compose.yaml**

```yaml
// highlight-next-line
name: kingsbridge
services:
  joomla:
    // highlight-next-line
    container_name: kingsbridge-app
    [...]

  joomladb:
    // highlight-next-line
    container_name: kingsbridge-db
    [...]
```

Nous n'allons pas encore redémarrer vos containers Docker. Pour l'instant, le nom kingsbridge ne sera pas pris en compte. Pour cela, il faudrait lancer `docker compose down` suivi de `docker compose up --detach`, mais attendons encore un peu avant de le faire.

## Les images Docker {#docker-images}

Si vous êtes curieux, vous pouvez lancer la commande `docker image list` pour obtenir la liste des images Docker déjà téléchargées sur votre machine.

```bash
$ docker image list

REPOSITORY TAG IMAGE ID CREATED SIZE
joomla latest 882b2151d890 2 days ago 663MB
mysql 8.0.13 102816b1ee7d 4 years ago 486MB
```

Ok, donc Docker a téléchargé Joomla (dans sa version *latest*) et MySQL (version 8.0.13).

**Comment utiliser une version spécifique de Joomla ?**

Par défaut, quand on ne précise aucun numéro de version (ce qui est déconseillé en production), Docker télécharge la version dite `latest`. `latest` est ce que Docker appelle un « tag ».

Pour que votre installation soit stable et prévisible, mieux vaut utiliser un tag de version précis. Vous trouverez tous les tags disponibles sur la [page officielle Joomla sur Docker Hub](https://hub.docker.com/_/joomla/tags).

Par exemple, pour utiliser Joomla 5.3.3 avec PHP 8.2, vous modifieriez la ligne `image` de votre `compose.yaml` comme ceci :

**compose.yaml**

```yaml
services:
  joomla:
    image: joomla:5.3.3-php8.2-apache

[...]
```

## Les containers Docker {#docker-containers}

Nous y sommes presque. Lancez `docker container list` pour obtenir la liste des containers créés par Docker :

```bash
$ docker container list

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0798f8f25d2b joomla "/entrypoint.sh apac…" 8 minutes ago Up 5 minutes 0.0.0.0:8080->80/tcp joomla-joomla-1
7b7fcd3809b0 mysql:8.0.13 "docker-entrypoint.s…" 8 minutes ago Up 7 minutes 3306/tcp, 33060/tcp joomla-joomladb-1
```

Nous avons deux containers en cours d'exécution (vos deux services). Faites attention à la colonne `PORTS` : votre container `joomla` écoute sur le port 8080 et votre container `mysql` écoute sur le port `3306`.

Hé, le port 8080, ça vous dit quelque chose ? C'est un port pour une page web, non ?

Essayons : démarrez votre navigateur préféré et allez sur `http://localhost:`8080 (*ou `http://127.0.0.1:8080`, c'est strictement pareil*) et... Waouh ! L'installateur Joomla montré au début de cet article vous attend.

## Installer Joomla {#install-joomla}

Retour sur `http://localhost:`8080 et continuons l'installation.

Sur le premier écran, sélectionnez simplement votre langue préférée puis saisissez un nom pour votre site Joomla :

> Screenshot — http\://localhost:8080
>
> ![Nommez votre site](./images/admin_step_1.webp)

Quand Joomla demandera vos identifiants d'administration, remplissez simplement les valeurs de votre choix :

> Screenshot — http\://localhost:8080
>
> ![Données de connexion](./images/joomla_admin_login_data.webp)

**En revanche, pour la configuration de la base de données, il faut être rigoureux :**

* Le type de base doit être `MySQLi` (puisque nous utilisons MySQL),

* Le nom de l'host doit être `joomladb` (le nom choisi pour le service de base de données),

* L'utilisateur doit être `root` (valeur par défaut) et

* Le mot de passe de cet utilisateur doit être `example`

> **Pourquoi ces valeurs ?:**
>
> Ces valeurs se retrouvent dans le fichier `compose.yaml`. Si vous avez nommé votre service de base de données autrement que `joomladb`, utilisez le nom que vous avez choisi.

**compose.yaml**

```yaml
services:
  [...]
  // highlight-next-line
  joomladb:
    [...]
    environment:
      // highlight-next-line
      - MYSQL_ROOT_PASSWORD=example
```

> Screenshot — http\://localhost:8080
>
> ![Configuration de la base de données Joomla](./images/joomla_admin_database_configuration.webp)

Et, après quelques secondes, tadaaa...

> Screenshot — http\://localhost:8080
>
> ![L'installation de Joomla est terminée](./images/joomla_admin_ready.webp)

La page d'administration :

> Screenshot — http\://localhost:8080/administrator
>
> ![L'installation de Joomla est terminée](./images/joomla_start_administrator.webp)

Et derrière, le tableau de bord d'administration montré au début de cet article.

**Félicitations, vous avez installé avec succès un site Joomla tout neuf avec Docker !**

## Tout se passe en RAM {#everything-is-done-in-ram}

Laissons le navigateur quelques minutes et retournons dans votre console Linux.

Au chapitre précédent, nous avons installé Joomla, donc nous devrions avoir Joomla sur votre ordinateur, non ?

Vérifions en revenant dans notre console Linux :

```bash
$ pwd
/tmp/joomla

$ ls -alh
total 12K
drwxr-xr-x 2 christophe christophe 4.0K Jan 4 15:31 .
drwxrwxrwt 12 root root 4.0K Jan 4 15:31 ..
-rw-r--r-- 1 christophe christophe 279 Jan 4 15:31 compose.yaml
```

Ah ? Rien... **Rien n'a été téléchargé dans votre dossier.** Vous n'avez pas Joomla sur votre ordinateur. Comment est-ce possible ?

Nous en reparlerons plus loin mais oui, par défaut avec Docker, tout se passe en mémoire, rien sur le disque. Si vous ne pouvez pas attendre, lisez mon article « [Partager des données entre votre container Docker et votre ordinateur](/blog/docker-volume) » pour mieux comprendre pourquoi et comment.

## Jouer avec les containers {#play-with-containers}

Toujours dans votre console, tapez à nouveau `docker container list` :

```bash
$ docker container list

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0798f8f25d2b joomla "/entrypoint.sh apac…" 8 minutes ago Up 5 minutes 0.0.0.0:8080->80/tcp joomla-joomla-1
7b7fcd3809b0 mysql:8.0.13 "docker-entrypoint.s…" 8 minutes ago Up 7 minutes 3306/tcp, 33060/tcp joomla-joomladb-1
```

Faites attention cette fois à la dernière colonne, appelée `NAMES`.

Nous avons donc deux containers, un nommé `joomla-joomla-1` et un nommé `joomla-joomladb-1`.

Nous allons les arrêter en lançant `docker compose down` :

```bash
$ docker compose down

[+] Running 3/3
✔ Container joomla-joomla-1 Removed 2.6s
✔ Container joomla-joomladb-1 Removed 4.2s
✔ Network joomla Removed
```

Si vous retournez sur `http://localhost:`8080 avec votre navigateur et que vous rafraîchissez la page, le site n'existe plus.

Relancez `docker compose up --detach`.

```bash
$ docker compose up --detach
```

Retournez sur le site, rafraîchissez la page et le site, ah, ne répond pas encore. Attendez un peu... encore un peu... et après un certain temps, le site sera là. Pourquoi ?

Docker doit (re)démarrer deux services, celui de Joomla et le serveur de base de données. L'initialisation des deux peut prendre quelques secondes, et le service de base de données doit être en route pour que Joomla puisse poursuivre son initialisation.

Vous pouvez le voir en lançant `docker compose logs --follow` (appuyez sur `CTRL`+`C` pour quitter).

```bash
$ docker compose logs --follow
```

Une fois Joomla prêt, vous retrouverez l'assistant d'installation de Joomla... comme la première fois. Donc, en lançant `docker compose down`, vous avez perdu votre travail.

```bash
$ docker compose down
```

> **Danger:**
>
> Comme mentionné plus haut, tout se passe en RAM. En arrêtant un container Docker, vous perdez tout ce qui n'est pas sauvegardé sur votre ordinateur. C'est parfait pour jouer/apprendre mais pas ce que vous attendez quand vous développez un vrai site.

> **Information:**
>
> Rappelez-vous de la modification faite plus tôt. Nous avions ajouté le nom kingsbridge comme nom de projet dans votre fichier `compose.yaml`, et nous avions nommé les deux containers. Vous pouvez voir qu'après avoir relancé `docker compose up`, ce n'est plus `joomla-joomlaxxxx` mais kingsbridge-app et kingsbridge-db. C'est parce que les modifications faites dans le fichier yaml ne sont prises en compte qu'après une commande `down / up`. Si vous modifiez le fichier yaml, vous devez redémarrer vos containers Docker.

## Synchroniser avec votre ordinateur {#synchronize-with-your-computer}

Nous allons maintenant demander à Docker de stocker des fichiers/dossiers sur votre ordinateur.

**Nous voulons deux choses :**

* Nous voulons que tout le site soit sauvegardé sur votre disque dur et

* nous voulons que la base de données soit sauvegardée sur le disque dur également.

Pour cela, éditez le fichier `compose.yaml` et ajoutez les lignes surlignées ci-dessous :

**compose.yaml**

```yaml
name: kingsbridge

services:
  joomla:
    image: joomla
    restart: always
    ports:
      - 8080:80
    environment:
      - JOOMLA_DB_HOST=joomladb
      - JOOMLA_DB_PASSWORD=example
    depends_on:
      joomladb:
        condition: service_healthy
    // highlight-next-line
    user: ${UID:-1000}:${GID:-1000}
    // highlight-next-line
    volumes:
      // highlight-next-line
      - ./site_joomla:/var/www/html

  joomladb:
    image: mysql:8.0.13
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=example
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      timeout: 20s
      retries: 10
    // highlight-next-line
    user: ${UID:-1000}:${GID:-1000}
    // highlight-next-line
    volumes:
      // highlight-next-line
      - ./db:/var/lib/mysql
```

Le dossier `/var/www/html` du service Joomla doit être synchronisé avec le sous-dossier `site_joomla` sur votre ordinateur. C'est pour le site Joomla.

Et le dossier `/var/lib/mysql` du service MySQL doit être synchronisé avec votre sous-dossier local `db`.

> **Créez d'abord les dossiers:**
>
> Veillez à créer d'abord ces deux répertoires sur votre ordinateur, comme ça les permissions des dossiers seront correctes !
>
> ```bash
> $ mkdir site_joomla db
> ```

Les deux lignes `user: ${UID:-1000}:${GID:-1000}` sont vraiment importantes et indiquent à Docker de réutiliser votre utilisateur local (celui de votre session Linux).

> **L'UID/GID de l'utilisateur:**
>
> Cette partie est cruciale : si vous tapez `id -u` et `id -g` sous Linux, vous obtiendrez votre propre user\_id et group\_id (autrement dit UID et GID). La plupart du temps, ce sera `1000` pour les deux mais... parfois non.
>
> La syntaxe `user: ${UID:-1000}:${GID:-1000}` signifie d'utiliser `1000` comme valeur par défaut sauf si les variables système `UID` et `GID` existent, auquel cas on utilise leurs valeurs.

Vérifiez simplement le contenu de votre dossier :

```bash
$ pwd
/tmp/joomla

$ ls -alh
total 20K
drwxr-xr-x 4 christophe christophe 4.0K Jan 4 15:57 .
drwxrwxrwt 12 root root 4.0K Jan 4 15:31 ..
-rw-r--r-- 1 christophe christophe 279 Jan 4 15:31 compose.yaml
drwxr-xr-x 2 christophe christophe 4.0K Jan 4 15:57 db
drwxr-xr-x 2 christophe christophe 4.0K Jan 4 15:57 site_joomla
```

Relancez Docker mais avant, assurez-vous que les containers précédents ont bien été supprimés (et pas seulement arrêtés) : `docker compose kill`.

```bash
$ docker compose kill

[+] Killing 2/2
✔ Container kingsbridge-db Killed 2.1s
✔ Container kingsbridge-app Killed 1.5s
```

Lancez maintenant la commande suivante et, comme vous le voyez, nous initialisons d'abord les variables UID et GID pour ne pas rencontrer de problèmes de permissions :

```bash
$ UID=$(id -u) GID=$(id -g) docker compose up --detach

[+] Running 3/3
✔ Network kingsbridge_default Created 0.3s
✔ Container kingsbridge-db Started 3.3s
✔ Container kingsbridge-app Started
```

Et vous pouvez déjà relancer `ls` pour constater que, oui, vos dossiers locaux `site_joomla` et `db` sont maintenant remplis. C'est le résultat de l'entrée `volumes` ajoutée dans votre `compose.yaml`.

```bash
$ pwd
/tmp/joomla

$ ls -alh site_joomla
total 132K
drwxr-xr-x 19 christophe christophe 4.0K Jan 4 15:59 .
drwxr-xr-x 4 christophe christophe 4.0K Jan 4 15:57 ..
-rw-r--r-- 1 christophe christophe 6.8K Jan 4 15:59 .htaccess
-rw-r--r-- 1 christophe christophe 18K Nov 19 19:54 LICENSE.txt
-rw-r--r-- 1 christophe christophe 5.2K Nov 19 19:54 README.txt
drwxr-xr-x 11 christophe christophe 4.0K Nov 19 19:54 administrator
drwxr-xr-x 5 christophe christophe 4.0K Nov 19 19:54 api
drwxr-xr-x 2 christophe christophe 4.0K Nov 19 19:54 cache
drwxr-xr-x 2 christophe christophe 4.0K Nov 19 19:54 cli
drwxr-xr-x 18 christophe christophe 4.0K Nov 19 19:54 components
drwxr-xr-x 2 christophe christophe 4.0K Nov 19 19:54 files
-rw-r--r-- 1 christophe christophe 6.8K Nov 19 19:54 htaccess.txt
drwxr-xr-x 5 christophe christophe 4.0K Nov 19 19:54 images
drwxr-xr-x 2 christophe christophe 4.0K Nov 19 19:54 includes
-rw-r--r-- 1 christophe christophe 1.6K Nov 19 19:54 index.php
drwxr-xr-x 10 christophe christophe 4.0K Nov 19 19:54 installation
drwxr-xr-x 4 christophe christophe 4.0K Nov 19 19:54 language
drwxr-xr-x 6 christophe christophe 4.0K Nov 19 19:54 layouts
drwxr-xr-x 6 christophe christophe 4.0K Nov 19 19:57 libraries
drwxr-xr-x 75 christophe christophe 4.0K Nov 19 19:58 media
drwxr-xr-x 27 christophe christophe 4.0K Nov 19 19:54 modules
drwxr-xr-x 26 christophe christophe 4.0K Nov 19 19:54 plugins
-rw-r--r-- 1 christophe christophe 764 Nov 19 19:54 robots.txt.dist
drwxr-xr-x 5 christophe christophe 4.0K Nov 19 19:54 templates
drwxr-xr-x 2 christophe christophe 4.0K Nov 19 19:54 tmp
-rw-r--r-- 1 christophe christophe 3.0K Nov 19 19:54 web.config.txt

$ ls -alh db
total 176M
drwxr-x--- 2 christophe christophe 4.0K Jan 4 15:59 '#innodb_temp'
drwxr-xr-x 7 christophe christophe 4.0K Jan 4 15:59 .
drwxr-xr-x 4 christophe christophe 4.0K Jan 4 15:57 ..
-rw-r----- 1 christophe christophe 56 Jan 4 15:59 auto.cnf
-rw-r----- 1 christophe christophe 3.0M Jan 4 15:59 binlog.000001
-rw-r----- 1 christophe christophe 358 Jan 4 15:59 binlog.000002
-rw-r----- 1 christophe christophe 32 Jan 4 15:59 binlog.index
-rw------- 1 christophe christophe 1.7K Jan 4 15:59 ca-key.pem
-rw-r--r-- 1 christophe christophe 1.1K Jan 4 15:59 ca.pem
-rw-r--r-- 1 christophe christophe 1.1K Jan 4 15:59 client-cert.pem
-rw------- 1 christophe christophe 1.7K Jan 4 15:59 client-key.pem
-rw-r----- 1 christophe christophe 5.9K Jan 4 15:59 ib_buffer_pool
-rw-r----- 1 christophe christophe 48M Jan 4 15:59 ib_logfile0
-rw-r----- 1 christophe christophe 48M Jan 4 15:59 ib_logfile1
-rw-r----- 1 christophe christophe 12M Jan 4 15:59 ibdata1
-rw-r----- 1 christophe christophe 12M Jan 4 15:59 ibtmp1
drwxr-x--- 2 christophe christophe 4.0K Jan 4 15:59 joomla
drwxr-x--- 2 christophe christophe 4.0K Jan 4 15:59 mysql
-rw-r----- 1 christophe christophe 30M Jan 4 15:59 mysql.ibd
drwxr-x--- 2 christophe christophe 4.0K Jan 4 15:59 performance_schema
-rw------- 1 christophe christophe 1.7K Jan 4 15:59 private_key.pem
-rw-r--r-- 1 christophe christophe 452 Jan 4 15:59 public_key.pem
-rw-r--r-- 1 christophe christophe 1.1K Jan 4 15:59 server-cert.pem
-rw------- 1 christophe christophe 1.7K Jan 4 15:59 server-key.pem
drwxr-x--- 2 christophe christophe 4.0K Jan 4 15:59 sys
-rw-r----- 1 christophe christophe 12M Jan 4 15:59 undo_001
-rw-r----- 1 christophe christophe 10M Jan 4 15:59 undo_002
```

Retournez dans votre navigateur et poursuivez l'installation de Joomla comme au chapitre précédent.

Quand l'assistant d'installation s'est terminé avec succès, revenez dans votre console Linux et vérifiez si vous voyez le fichier `configuration.php` maintenant.

```bash
$ pwd
/tmp/joomla

$ ls site_joomla/configuration.php
.rw-r--r-- 2.0k christophe christophe 6.8K Jan 4 15:59 .htaccess

$ head -n 10 site_joomla/configuration.php
{`<?php
class JConfig \{
        public \$offline = false;
        public \$offline_message = 'Ce site est en maintenance.<br>Merci de revenir ultérieurement.';
        public \$display_offline_message = 1;
        public \$offline_image = '';
        public \$sitename = 'kingsbridge';
        public \$editor = 'tinymce';
        public \$captcha = '0';
        public \$list_limit = 20;
`}
```

Oui ! Cette fois, votre site Joomla est stocké sur votre ordinateur.

Pour l'exercice, tuons vos containers avec `docker compose kill` puis relançons `docker compose up --detach` pour les redémarrer : cette fois, nous retrouverons votre site Joomla tel que nous l'avons laissé. Plus rien n'est perdu.

```bash
$ docker compose kill && docker compose up --detach
```

Et puisque les fichiers/dossiers sont maintenant sur votre ordinateur, vous pouvez en faire ce que vous voulez, comme les commiter dans un repository GitHub par exemple.

> **La synchronisation a un coût:**
>
> Quand vous utilisez un ou plusieurs volumes, Docker doit vérifier en permanence si les fichiers/dossiers de votre ordinateur sont synchronisés avec les containers. Cela a un coût en performances. De même, si Docker doit écrire dans un fichier (ou dans votre base Joomla) ; si c'est uniquement en mémoire, ce sera plus rapide que s'il faut aussi écrire la base sur votre disque. Cela dit, la différence de vitesse n'est pas flagrante en temps normal. Si vous êtes développeur et que vous écrivez des centaines voire des milliers d'enregistrements, vous verrez une différence notable.

## Lancer une commande CLI {#start-a-cli-command}

Quand vous travaillez sur un site Joomla, vous avez parfois besoin de lancer une commande PHP comme `php joomla.php`.

Pour cela, vous devez démarrer une *session shell interactive* dans le container Joomla.

Vous vous souvenez du nom de votre service Joomla ? Sinon, rouvrez simplement le fichier `compose.yaml`.

**compose.yaml**

```yaml
services:
  // highlight-next-line
  joomla:
    [...]
```

Le nom de votre service Joomla est `joomla` (et `joomladb` est le nom de votre service de base de données).

Nous savons maintenant tout ce qu'il faut : pour lancer une session shell interactive dans le container Joomla, il suffit de lancer `docker compose exec joomla /bin/sh` pour *sauter* dans le container Joomla (*et `docker compose exec joomladb /bin/sh` pour le container de la base de données*).

```bash
$ docker compose exec joomla /bin/sh
```

Rembobinons quelques secondes parce que c'est compliqué à saisir.

Sur votre ordinateur, dans votre console Linux, si vous tapez `pwd` pour connaître le dossier courant, vous verrez `/tmp/joomla` puisque c'est le répertoire utilisé dans ce tutoriel.

Ensuite, nous sautons dans le container Docker Joomla en lançant `docker compose exec joomla /bin/sh` et, vous le voyez, nous n'avons plus un prompt qui commence par `>` mais par `$`, et ce n'est pas la seule différence. Si maintenant nous relançons `pwd`, nous ne sommes plus dans votre dossier `/tmp/joomla` mais dans `/var/www/html`.

Ça peut rendre fou mais... quand vous entrez dans le container Docker, vous n'êtes *plus* sur votre ordinateur, vous êtes virtuellement sur un autre ordinateur, le container. Dans cet *ordinateur*, le dossier courant est donc `/var/www/html`. En tapant `exit`, vous quittez le container, vous revenez sur votre ordinateur et dans le dossier `/tmp/joomla`.

```bash
$ pwd
/tmp/joomla

$ docker compose exec joomla /bin/sh

$ pwd
/var/www/html

$ exit

$ pwd
/tmp/joomla
```

Autre chose à essayer :

```bash
$ php --version
command not found: php

$ docker compose exec joomla /bin/sh

$ php --version
PHP 8.3.29 (cli) (built: Dec 29 2025 23:29:22) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.29, Copyright (c) Zend Technologies
with Zend OPcache v8.3.29, Copyright (c), by Zend Technologies

$ exit
```

Donc, sur mon ordinateur (et probablement sur le vôtre), en tapant `php --version`, j'obtiens une erreur. C'est normal. Je n'ai pas PHP sur mon ordinateur. *Je travaille avec PHP au quotidien depuis des années et je ne l'ai pas sur ma machine.* 😄

Ensuite je saute dans le container Joomla, je retape la même commande et, oui, dans le container Docker de Joomla, PHP est bien installé et ici, c'est la version 8.3.29.

## Utiliser un alias {#using-alias}

Docker démarrera toujours votre projet sur votre localhost et sur un port du type `http://127.0.0.1:`8080.

Plutôt que d'utiliser l'adresse IP, ce serait bien plus agréable d'utiliser un alias comme `http://`kingsbridge`:`8080.

Pour cela, sous Windows, éditez le fichier `C:\Windows\System32\Drivers\etc\hosts` et ajoutez la ligne kingsbridge comme illustré ci-dessous :

**C:\Windows\System32\Drivers\etc\hosts**

```
127.0.0.1 localhost
// highlight-next-line
127.0.0.1 kingsbridge
```

Enregistrez le fichier. Vous pouvez maintenant aller sur `http://`kingsbridge`:`8080

> Screenshot — http\://kingsbridge:8080
>
> ![Utilisation de l'alias Kingsbridge](./images/using_alias.webp)

> **Note:**
>
> Quand ils créent un alias dans le fichier hosts, certains préfèrent utiliser
> le suffixe `.local` comme dans `127.0.0.1` kingsbridge`.local` pour
> bien montrer qu'il s'agit d'un site local. Si vous préférez ça, l'URL sera
> `http://`
> kingsbridge`.local:`8080

## Utiliser un autre port {#using-another-port}

Imaginez que vous ayez un autre projet, pas `Kingsbridge` cette fois. Pouvez-vous faire tourner plusieurs projets Docker en même temps ? Oui, bien sûr !

Il faut juste veiller à utiliser un autre port, non utilisé.

Prenons le fichier `compose.yaml` du projet `shiring`

**compose.yaml**

```yaml
// highlight-next-line
name: shiring

services:
  joomla:
    image: joomla
    ports:
      // highlight-next-line
      - 8081:80

  [...]
```

Nous allons utiliser le port `8081` pour ce projet et, dans votre fichier hosts, nous ajouterons `127.0.0.1 shiring`.

Donc, maintenant et en même temps, nous pouvons accéder à `http://`kingsbridge`:`8080 et à `http://shiring:8081` sans conflits puisque nous avons utilisé un numéro de port distinct.

Kingsbridge peut être un site Joomla 4.4 / PHP 7.4 tandis que shiring tourne sur Joomla 5.0 / PHP 8.2, sans le moindre conflit. **Et c'est d'une simplicité stupéfiante, quand on repense à la façon dont on travaillait avant Docker.**

> **Information:**
>
> Utiliser un autre port n'est pas obligatoire. Vous pouvez avoir plusieurs sites sur le même port, par exemple 8080. Mais dans ce cas, vous ne pourrez pas les utiliser en même temps. Vous pouvez démarrer le premier et, en essayant de démarrer le second, Docker dira *port already in use*. Ce n'est pas un problème ; lancez simplement `docker compose stop` pour le premier afin de libérer le port, puis démarrez le second.
>
> ```bash
> $ docker compose stop
> ```

> **Note:**
>
> Dans cet article, j'utilise le port 8080 parce que Joomla l'utilise
> dans son fichier `compose.yaml` par défaut. Vous n'êtes pas obligé de le
> garder, vous pouvez parfaitement utiliser `80` et pas 8080. Dans mon
> travail quotidien, j'utilise les ports `80`, `81`, `82`, `83`, ... en variant
> le second chiffre pour mes projets.

## Vous préférez PostgreSQL ou MariaDB {#did-you-prefer-postgresql-or-mariadb}

Jusqu'ici, nous avons choisi MySQL comme gestionnaire de base de données. Notre fichier `compose.yaml` est celui, légèrement modifié, que l'on trouve sur <https://hub.docker.com/_/joomla>.

Pourriez-vous opter pour autre chose que MySQL ? Bien sûr, tant que Joomla supporte ce système (voir <https://manual.joomla.org/docs/next/get-started/technical-requirements/>).

Il suffit de remplacer le service `joomladb`, de ne plus utiliser `mysql` mais celui que nous voulons.

**Utiliser PostgreSQL**

Essayons PostgreSQL... Nous allons remplacer `mysql`. L'image Docker officielle de PostgreSQL se trouve sur <https://hub.docker.com/_/postgres>. La documentation nous indique quelle `image` utiliser et comment définir des variables comme le mot de passe par défaut (`POSTGRES_PASSWORD`).

Nous devons aussi changer quelques variables :

* L'utilisateur par défaut de la base doit être précisé, ce sera par exemple `postgres`,
* Nous devons aussi définir le nom de la base dans les deux services ; nous l'appellerons `joomla_db` et
* Nous devons indiquer à Joomla que nous utilisons PostgreSQL, il faut donc mettre `JOOMLA_DB_TYPE` à `pgsql` (soit `mysql`, soit `pgsql`).

> **Note:**
>
> Cette information provient de cette pull request :
> <https://github.com/joomla-docker/docker-joomla/pull/156>.

Notre `compose.yaml` devient :

**compose.yaml**

```yaml
name: kingsbridge

services:
  joomla:
    image: joomla
    container_name: kingsbridge-app
    restart: always
    ports:
      - 8080:80
    environment:
      - JOOMLA_DB_HOST=joomladb
      // highlight-next-line
      - JOOMLA_DB_USER=postgres
      - JOOMLA_DB_PASSWORD=example
      // highlight-next-line
      - JOOMLA_DB_NAME=joomla_db
      // highlight-next-line
      - JOOMLA_DB_TYPE=pgsql
    depends_on:
      - joomladb

  joomladb:
    // highlight-next-line
    image: postgres:16.0-alpine
    container_name: kingsbridge-db
    restart: always
    environment:
      // highlight-next-line
      - POSTGRES_DB=joomla_db
      // highlight-next-line
      - POSTGRES_USER=postgres
      // highlight-next-line
      - POSTGRES_PASSWORD=example
```

Maintenant, pendant la configuration de Joomla, veillez à choisir `PostgreSQL (PDO)` comme type de base et à remplir l'assistant avec les bonnes valeurs.

> **Utilisez des images alpine dès que possible:**
>
> Pour la première fois dans ce tutoriel, nous utilisons une image `alpine` (`postgres:16.0-alpine` ici). Ces images sont plus légères qu'une image non-alpine. Elles contiennent le strict nécessaire pour faire tourner le service, alors qu'une image *traditionnelle* contient des outils, binaires... supplémentaires dont vous pourriez avoir besoin mais que vous n'utiliserez pas forcément.

**Utiliser MariaDB**

Si vous comptez utiliser MariaDB, voici l'image officielle Docker : <https://hub.docker.com/_/mariadb>.

**compose.yaml**

```yaml
name: kingsbridge

services:
  joomla:
    image: joomla
    container_name: kingsbridge-app
    restart: always
    ports:
      - 8080:80
    environment:
      - JOOMLA_DB_HOST=joomladb
      - JOOMLA_DB_PASSWORD=example
    depends_on:
      - joomladb

  joomladb:
    // highlight-next-line
    image: mariadb:11.1.2
    container_name: kingsbridge-db
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=example
```

Pour MariaDB, sélectionnez `MySQLi` dans l'assistant d'installation.

## Informations complémentaires {#extra-information}

### Le container sera redémarré par Windows {#the-container-will-be-restarted-by-windows}

Si vous éteignez votre ordinateur alors qu'un ou plusieurs containers tournent encore, Docker les relancera au démarrage suivant.

Autrement dit, la prochaine fois que vous démarrez votre ordinateur, votre site sera toujours accessible et vous n'aurez pas une seule commande à lancer. C'est tellement simple !

### Travailler avec Windows {#working-with-windows}

Imaginez que vous soyez dans votre console (par exemple après un `cd /tmp/joomla` dans la console Linux) et que vous vouliez ouvrir le site avec Visual Studio Code, déjà installé sur votre machine Windows.

C'est facile : lancez simplement `code .` pour ouvrir le dossier courant, donc votre projet, dans vscode.

Autre cas d'usage : vous voulez démarrer l'Explorateur Windows et naviguer dans la structure de votre projet. Là aussi c'est possible, lancez simplement `explorer.exe .` pour l'ouvrir sur le répertoire courant. Voyez mon article « [Ouvrir votre dossier Linux dans l'Explorateur Windows](/blog/wsl-windows-explorer) » pour en savoir plus sur cette fonctionnalité.

## Bonus - Installer Joomla avec une seule ligne de commande {#bonus---install-joomla-with-a-cli-one-liner}

Le `compose.yaml` utilisé au début de cet article était le minimum. Voici la version **finale**, avec tout ce que nous avons ajouté depuis : un nom de projet, des noms de containers explicites et les deux volumes pour que votre site et votre base survivent à un `docker compose down`.

Cliquez simplement sur `Generate install script` ci-dessous, copiez/collez le script dans votre console, exécutez-le et suivez les instructions. Après quelques secondes, vous aurez un site Joomla fonctionnel — un que vous pourrez vraiment garder.

**Project: /tmp/joomla**

> **Note:**
>
> Maintenant, lancez 'UID=$(id -u) GID=$(id -g) docker compose up --detach'
> pour créer votre site Joomla. Patientez un peu et ouvrez votre navigateur,
> rendez-vous sur <http://localhost:8080> pour ouvrir votre site Joomla. Le type
> de base de données doit être `MySQLi`, le nom de l'host doit être
> `joomladb`, l'utilisateur doit être `root` et le mot de passe de cet
> utilisateur doit être `example`.

**compose.yaml**

```yaml
name: yourprojectname

services:
  joomla:
    image: joomla:6.0.1-php8.3-apache
    container_name: kingsbridge-app
    restart: always
    ports:
      - 8080:80
    environment:
      - JOOMLA_DB_HOST=joomladb
      - JOOMLA_DB_PASSWORD=example
    depends_on:
      joomladb:
        condition: service_healthy
    user: ${UID:-1000}:${GID:-1000}
    volumes:
      - ./site_joomla:/var/www/html

  joomladb:
    image: mysql:8.0.13
    container_name: kingsbridge-db
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=example
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10
    user: ${UID:-1000}:${GID:-1000}
    volumes:
      - ./db:/var/lib/mysql
```

(create empty directory: site\_joomla)

(create empty directory: db)

> **Caution:**
>
> Veillez, pour chaque projet, à mettre à jour la ligne `name:` et, si vous comptez faire tourner vos sites Joomla en parallèle, à mettre à jour le numéro de port de Joomla en en choisissant un nouveau à chaque fois (ce peut être `80`, `81`, `82` et ainsi de suite).

## Conclusion {#conclusion}

Ce que je préfère dans cette approche, ce n'est pas la vitesse — c'est qu'un site Joomla devient un *dossier*. Un `compose.yaml`, deux sous-dossiers, et vous pouvez en avoir cinq côte à côte, chacun sur son port, chacun avec sa base, sans qu'aucun ne puisse casser les autres. Supprimer un site, c'est supprimer un dossier.

À partir d'ici, deux suites naturelles : [Create your Joomla website using Docker - Part 2](/blog/docker-joomla-part-2) va plus loin sur le workflow au quotidien, et [Utiliser Adminer, pgadmin ou phpmyadmin](/blog/docker-adminer-pgadmin-phpmyadmin) montre comment parcourir la base de données qui vient d'être créée pour vous.
