Pourquoi mettre à jour l'application ne change pas le PHP
Une mise à jour de WordPress, un composer update ou une nouvelle version de Nextcloud remplacent des fichiers de l'application. L'interpréteur PHP, lui, est un programme installé dans l'image Docker, au même titre que le système Debian ou Alpine qui l'entoure. Tant que l'image ne change pas, le PHP ne change pas, quel que soit le nombre de mises à jour de l'application.
Le second piège est le redémarrage. docker restart relance le conteneur existant, donc la même image. docker compose up -d ne va pas chercher une version plus récente quand une image portant ce nom existe déjà sur le serveur : il réutilise la copie locale. Seul un pull ou un build --pull, suivi d'une recréation du conteneur, change l'interpréteur.
Les deux failles et les commandes apt ou dnf sont détaillées dans notre guide de mise à jour de PHP. Ici, il s'agit de l'image Docker et de la preuve qu'elle est la bonne.
Six objets à ne pas confondre
- L'image du registre — ce que Docker Hub ou votre registre privé sert aujourd'hui sous une étiquette comme
php:8.3-fpm. Une étiquette est mobile : elle pointe vers un autre contenu après chaque reconstruction. - L'image locale — la copie présente sur votre serveur, visible avec
docker image ls. Elle ne bouge que si vous tirez ou construisez une image. - Le conteneur en cours — il garde l'identifiant de l'image avec laquelle il a été créé, même si une image plus récente porte désormais le même nom.
- Le processus qui répond — PHP-FPM, Apache avec
mod_phpou FrankenPHP. C'est lui qui est exposé, etphp -vne l'interroge pas. - Les autres services — worker de file, planificateur, conteneur
clide maintenance : chacun a sa propre image, donc sa propre version de PHP. - Le cache de construction — une couche
FROMen cache peut rejouer l'ancienne base sans qu'aucune erreur ne s'affiche.
Comparer le registre, l'image locale et le conteneur
Lister les images locales et leur date
docker image ls php(ouwordpress,nextcloud). La colonneCREATEDindique quand l'image a été construite. Une imagephp:8.3-fpmcréée avant le 21 octobre 2026 ne contient pas le correctif.Lire l'image de chaque conteneur
docker psaffiche dans la colonneIMAGEl'étiquette demandée à la création. Pour obtenir l'identifiant réel de l'image utilisée, interrogez le conteneur :docker inspect --format '{{.Image}}' <conteneur>.Comparer avec l'image présente sur le disque
docker image inspect --format '{{.Id}}' php:8.3-fpmrend l'identifiant de l'image qui porte aujourd'hui ce nom. Si cet identifiant diffère de celui du conteneur, le conteneur tourne sur une image plus ancienne que celle du disque : il n'a jamais été recréé après le dernier tirage.Comparer avec le registre
docker pull php:8.3-fpmtermine par une ligneStatus: Downloaded newer image for …quand une image plus récente est arrivée, ouStatus: Image is up to date for …sinon. Dans le second cas, soit votre copie est déjà la dernière, soit l'étiquette n'a pas encore été republiée : confrontez-la à la date de l'étiquette sur Docker Hub.
Lire la version que le web sert vraiment
php -v interroge le programme en ligne de commande, pas le processus qui répond aux requêtes. La constante PHP_SAPI dit lequel parle : cli en ligne de commande, fpm-fcgi pour PHP-FPM, apache2handler pour Apache avec mod_php. Dans une image unique, les deux versions coïncident presque toujours. L'écart apparaît dans trois situations courantes avec Docker : un docker compose run démarre un conteneur neuf, donc depuis l'image locale la plus récente, alors que le service web tourne toujours sur l'ancienne ; un conteneur cli de maintenance est bâti sur une autre étiquette que le service web ; un reverse proxy renvoie vers un autre conteneur que celui que vous inspectez.
La preuve la plus fiable reste la requête HTTP : elle suit le chemin d'un visiteur et lit PHP_VERSION dans le processus qui répond. Le binaire FPM se contrôle en complément avec docker exec <conteneur> php-fpm -v.
Prouver la version servie, service par service
Déposer un fichier de test dans le dossier servi
Exemple avec le service
wordpressde l'image officielle, dont le dossier web est/var/www/html(adaptez le service et le chemin à votre stack) :docker compose exec wordpress sh -c 'echo "<?php echo PHP_VERSION, \" \", PHP_SAPI;" > /var/www/html/v-check.php'L'interroger par HTTP, puis le supprimer aussitôt
curl -s https://votre-domaine.com/v-check.phppuisdocker compose exec wordpress rm /var/www/html/v-check.php. La réponse donne la version suivie du SAPI. Comparez-la aux versions corrigées : 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 selon la branche. Un numéro inférieur pour votre branche signifie que le correctif n'est pas là.Contrôler le binaire FPM du conteneur
docker exec <conteneur> php-fpm -vaffiche la version et le SAPI du binaire FPM de ce conteneur précis. Avec une image Apache, la requête HTTP de l'étape précédente suffit :mod_phpest chargé par Apache.Ne pas se fier à docker compose run
docker compose runcrée un conteneur neuf à partir de l'image locale. Il peut annoncer la version corrigée pendant que le conteneur du site, lui, n'a pas bougé. Contrôlez toujours le conteneur qui reçoit le trafic.
Tags flottants et tags pinnés : qui avance tout seul
Une étiquette de branche comme php:8.3-fpm avance au prochain pull : elle pointe alors vers la version corrigée. Une étiquette exacte comme php:8.3.36-fpm reste sur sa version, et une référence par empreinte (@sha256:…) ne bouge jamais. La documentation de docker image pull est explicite : avec une empreinte, Docker ne récupère aucune reconstruction, correctifs de sécurité compris, tant que vous ne changez pas l'empreinte vous-même.
Les étiquettes corrigées de l'image officielle php sont arrivées sur Docker Hub dans la journée et la soirée du 21 octobre 2026 (UTC), pour les variantes FPM des branches 8.5, 8.4, 8.3 et 8.2. Les images WordPress officielles php8.3-fpm, php8.4-fpm et php8.3-apache ont été republiées le 22 octobre 2026 au petit matin (UTC), et celles de Nextcloud le même jour. Une image tirée avant ces moments est donc l'ancienne, même si son nom est identique. Relisez ces dates sur la page de chaque étiquette. La branche 8.2 reçoit son correctif mais atteint sa fin de vie le 31 décembre 2026 : planifiez son remplacement.
Quelle écriture avance, laquelle reste figée
Faites défiler le tableau
| Dans votre compose ou Dockerfile | Avance au prochain pull ? | Pour obtenir le PHP corrigé |
|---|---|---|
| `php:8.3-fpm` | Oui, l'étiquette est republiée | `pull` ou `build --pull`, puis recréer le conteneur |
| `php:8.3.36-fpm` | Non, version exacte | Déjà corrigé ; à changer à la main au prochain correctif |
| `php:8.3.<n>-fpm` avec n inférieur à 36 | Non, version exacte | Passer à une étiquette corrigée, reconstruire, recréer |
| `wordpress:php8.3-fpm` | Oui, l'éditeur la republie | `pull`, puis recréer le service |
| `wordpress:<x.y>-php8.3-fpm` | Oui pour le PHP : l'éditeur la republie | `pull`, puis recréer le service |
| `php:8.3-fpm@sha256:…` | Jamais | Remplacer l'empreinte par celle d'une image corrigée |
| `FROM php:8.3-fpm` dans votre Dockerfile | Seulement si vous construisez avec `--pull` | `build --pull`, puis recréer le conteneur |
| `image: monregistre/app:latest` (votre image) | Non, c'est votre dernière construction | Reconstruire, republier, puis tirer et recréer |
Image maison : la séquence et ce que chaque option change
Pour une image construite chez vous à partir de FROM php:8.3-fpm, la séquence tient en trois commandes : docker compose build --pull --no-cache, puis docker compose up -d --force-recreate, puis le contrôle de la version servie. Chacune répond à un piège précis.
--pull est l'option qui change la version de PHP : elle demande à Docker de chercher une version plus récente de l'image de base au lieu de réutiliser celle du serveur. Sans elle, le FROM est résolu avec la copie locale, et la construction réussit avec l'ancien interpréteur, sans le moindre message.
--no-cache rejoue toutes les couches, y compris apt-get et composer install, ce qui renouvelle aussi les bibliothèques système et les dépendances. Il n'est pas nécessaire pour changer de PHP, car quand l'image de base change, les couches suivantes sont reconstruites d'elles-mêmes. Il sert quand une couche en cache fige un paquet à renouveler.
--force-recreate recrée les conteneurs même si Compose estime que leur configuration et leur image n'ont pas changé. C'est ce qui supprime le doute sur ce qui tourne.
Reconstruire ses images à chaque correctif est un calendrier à tenir, pas un geste unique. Sur un VPS en accès root, ce calendrier est le vôtre, et notre guide d'installation de Docker sur VPS pose la base de travail.
Reconstruire et recréer une image maison
Vérifier que l'étiquette de base est corrigée
Ouvrez la page de votre étiquette de base sur Docker Hub et vérifiez qu'elle a été publiée à partir du 21 octobre 2026. Si votre
FROMvise une version exacte plus ancienne, changez-la d'abord.Reconstruire en tirant la base
docker compose build --pull --no-cache. Notez la version avant l'opération avec le fichier de test, pour avoir un avant et un après.Recréer les conteneurs
docker compose up -d --force-recreate. Une seule commande peut aussi enchaîner les trois temps :docker compose up -d --build --pull always. Recréez tous les services qui utilisent l'image : web, worker de file, planificateur.Prouver le résultat
Relancez le fichier de test, puis comparez l'identifiant donné par
docker inspect --format '{{.Image}}' <conteneur>à celui dedocker image ls. L'ancienne et la nouvelle image peuvent porter le même nom : seuls l'identifiant et la réponse HTTP font foi.
WordPress et Nextcloud officiels : le PHP vient de l'étiquette
Une étiquette WordPress combine une version de WordPress, une version de PHP et une variante, par exemple php8.3-apache ou php8.3-fpm. La branche PHP est choisie par le nom de l'étiquette. Changer de version de WordPress, ou laisser les mises à jour automatiques agir dans le volume de données, ne touche pas à cette branche. Pour obtenir le PHP corrigé, il faut re-tirer l'étiquette avec docker compose pull, puis recréer le service. La variante Apache est la variante par défaut, et elle charge PHP en mod_php : c'est celle que le projet PHP juge la plus exposée, avec un exploit démontré avant l'exécution du moindre code applicatif. Traitez-la en priorité.
Nextcloud suit le même principe, en deux variantes : apache embarque un Apache complet, fpm demande un serveur web devant lui. La documentation de l'image décrit la mise à jour comme un remplacement : tirer l'image, jeter l'ancien conteneur, démarrer le nouveau. Le code de Nextcloud et vos données vivent dans le volume /var/www/html, que la recréation du conteneur n'efface pas. Voir notre guide WordPress sur VPS et celui de Nextcloud.
Laravel Octane et FrankenPHP : le moteur est dans l'image
Avec Octane et FrankenPHP, il n'y a pas de PHP-FPM : le serveur d'application embarque l'interpréteur. Les images officielles de FrankenPHP reposent sur les images PHP officielles, et leur étiquette combine la version de FrankenPHP, celle de PHP et le système, sous la forme dunglas/frankenphp:<version>-php8.4-trixie. Le projet les reconstruit à chaque version et, chaque jour à 4 h UTC, si de nouvelles images PHP officielles existent. Votre FROM dunglas/frankenphp ne reçoit le correctif que si vous reconstruisez votre image avec --pull.
Le piège propre à Octane est le worker. Octane démarre l'application une fois et la garde en mémoire : php artisan octane:reload relance proprement les workers pour charger le code déployé. C'est le bon geste après un déploiement de code, mais il ne remplace pas l'interpréteur, qui reste celui de l'image en cours. Il en va de même pour un kill -USR2 ou un rechargement de PHP-FPM lancé dans l'ancien conteneur : ils relancent les mêmes fichiers, ceux de l'ancienne image. Pour changer de PHP, recréez le conteneur, y compris ceux des workers de file et du planificateur. Voir notre guide Laravel Octane sur VPS.
Pièges d'infrastructure qui rejouent l'ancienne image
- Cache de build de la CI — un cache de couches restauré peut rejouer la couche
FROM. Ajoutez--pullà la commande de build de la CI, ou invalidez le cache pour cette étape. - Registre privé ou miroir — si vos serveurs tirent depuis un registre interne qui copie les images à la main ou par tâche planifiée, vérifiez qu'il a recopié l'étiquette. Sinon
pullrépondImage is up to datealors que l'éditeur a republié. - Stack Portainer ou outil d'orchestration — la mise à jour d'une stack ne re-tire pas toujours l'image. Cochez l'option de re-téléchargement avant le redéploiement si votre outil en propose une.
pull_policy: missing— c'est la valeur par défaut de Compose sans sectionbuild: il ne tire que si l'image est absente du serveur. Seule l'étiquettelatestest tirée dans tous les cas. Utilisezalways, oudailyetweeklypour vérifier le registre à intervalle fixe.- Un service oublié — web, worker, planificateur et conteneur
cliconstruits depuis des Dockerfile séparés ont chacun leur base : corrigez-les tous. - Un conteneur orphelin — un
docker runoublié ou un autre projet Compose peut encore répondre sur un port. Listez tout ce qui tourne avecdocker ps.
Dépannage : ce que vous voyez, ce que cela veut dire
Faites défiler le tableau
| Ce que vous constatez | Cause probable | Remède |
|---|---|---|
| `pull` affiche `Status: Image is up to date` mais la version reste ancienne | L'étiquette n'a pas encore été republiée, ou vous tirez une version exacte ou une empreinte | Comparer avec la date de l'étiquette sur Docker Hub, puis passer à une étiquette corrigée |
| `up -d` ne change rien après un tirage | Le conteneur existant n'a pas été recréé | `docker compose up -d --force-recreate`, puis comparer les identifiants d'image |
| Le build se termine en quelques secondes, avec la base déjà en cache | `--pull` absent : la base du serveur est réutilisée | `docker compose build --pull`, avec `--no-cache` si des paquets système doivent aussi être renouvelés |
| `docker compose run` annonce la version corrigée, le site répond l'ancienne | `run` crée un conteneur neuf, le service web n'a pas été recréé | Contrôler par HTTP le conteneur qui reçoit le trafic, puis le recréer |
| La version est bonne mais un worker se comporte comme avant | Un worker de file ou Octane tourne encore dans un ancien conteneur | Recréer tous les conteneurs qui utilisent l'image, pas seulement le service web |