[{"data":1,"prerenderedAt":252},["ShallowReactive",2],{"seo-verification":3,"blog-php2shell-docker-rebuild-php-wordpress-images-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-php2shell-docker-rebuild-php-wordpress-images-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":190,"ctaBody":191,"ctaButton":192,"ctaUrl":193,"relatedPosts":194},501,"php2shell-docker-rebuild-php-wordpress-images",{"fr":12,"en":10,"ar":13,"es":14},"php2shell-docker-wordpress-reconstruire-images-php","php2shell-docker-إعادة-بناء-صور-php-ووردبريس","php2shell-docker-reconstruir-imagenes-php-wordpress","PHP2Shell and Docker: rebuild your PHP and WordPress images","An updated WordPress or Laravel does not change the PHP in your Docker image. Prove the served version, spot which tags moved and rebuild without traps.",12,0,false,"2026-10-23T00:00:00+00:00","2026-10-23T23:43:01+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},8,"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fphp2shell-docker-wordpress-reconstruire-images-php-poster.svg",{"categorySlug":34,"appSlug":35},"cms-websites","wordpress","You updated WordPress last week, restarted the container, and you assume you are covered against PHP2Shell. That is not certain: in a container, PHP lives in the image, not in the application, and a restart reuses the image already on disk. The PHP fixes 8.5.12, 8.4.27, 8.3.36 and 8.2.35 were released on October 21, 2026. This guide shows how to prove, container by container, which PHP really answers, then how to pull or rebuild the image that is not fixed, for WordPress, Nextcloud, Laravel Octane and a custom image.",[38,42,52,68,71,86,89,127,130,145,148,151,160,187],{"type":39,"title":40,"body":41},"h2","Why updating the application does not change PHP","A WordPress update, a `composer update` or a new Nextcloud release replaces application files. The PHP interpreter is a program installed in the Docker image, just like the Debian or Alpine system around it. As long as the image does not change, PHP does not change, however many times the application is updated.\n\nThe second trap is the restart. `docker restart` restarts the existing container, so the same image. `docker compose up -d` does not look for a newer version when an image with that name already exists on the server: it reuses the local copy. Only a `pull` or a `build --pull`, followed by recreating the container, changes the interpreter.\n\nThe two flaws and the `apt` or `dnf` commands are covered in \u003Ca href=\"\u002Fblog\u002Fphp2shell-cve-2026-109618-109619-mettre-a-jour-php\">our PHP update guide\u003C\u002Fa>. Here the subject is the Docker image and the proof that it is the right one.",{"type":43,"title":44,"items":45},"ul","Six objects not to confuse",[46,47,48,49,50,51],"**The registry image** — what Docker Hub or your private registry serves today under a tag such as `php:8.3-fpm`. A tag is mobile: it points to different content after every rebuild.","**The local image** — the copy on your server, visible with `docker image ls`. It only moves when you pull or build an image.","**The running container** — it keeps the ID of the image it was created from, even if a newer image now carries the same name.","**The process that answers** — PHP-FPM, Apache with `mod_php` or FrankenPHP. It is the exposed one, and `php -v` does not query it.","**The other services** — queue worker, scheduler, maintenance `cli` container: each has its own image, hence its own PHP version.","**The build cache** — a cached `FROM` layer can replay the old base without any error being shown.",{"type":53,"title":54,"steps":55},"steps","Compare the registry, the local image and the container",[56,59,62,65],{"title":57,"body":58},"List local images and their date","`docker image ls php` (or `wordpress`, `nextcloud`). The `CREATED` column shows when the image was built. A `php:8.3-fpm` image created before October 21, 2026 does not contain the fix.",{"title":60,"body":61},"Read each container's image","`docker ps` shows in the `IMAGE` column the tag requested at creation. To get the real ID of the image in use, query the container: `docker inspect --format '{{.Image}}' \u003Ccontainer>`.",{"title":63,"body":64},"Compare with the image on disk","`docker image inspect --format '{{.Id}}' php:8.3-fpm` returns the ID of the image that carries that name today. If it differs from the container's, the container runs on an image older than the one on disk: it was never recreated after the last pull.",{"title":66,"body":67},"Compare with the registry","`docker pull php:8.3-fpm` ends with `Status: Downloaded newer image for …` when a newer image arrived, or `Status: Image is up to date for …` otherwise. In the second case, either your copy is already the latest or the tag has not been republished yet: check it against the tag date on Docker Hub.",{"type":39,"title":69,"body":70},"Read the version the web really serves","`php -v` queries the command-line program, not the process that answers requests. The `PHP_SAPI` constant tells which one is speaking: `cli` on the command line, `fpm-fcgi` for PHP-FPM, `apache2handler` for Apache with `mod_php`. In a single image the two versions almost always match. The gap appears in three common Docker situations: a `docker compose run` starts a fresh container, so from the latest local image, while the web service still runs the old one; a maintenance `cli` container is built on a different tag than the web service; a reverse proxy forwards to a different container than the one you inspect.\n\nThe most reliable proof remains the HTTP request: it follows a visitor's path and reads `PHP_VERSION` in the process that answers. Check the FPM binary as a complement with `docker exec \u003Ccontainer> php-fpm -v`.",{"type":53,"title":72,"steps":73},"Prove the served version, service by service",[74,77,80,83],{"title":75,"body":76},"Drop a test file in the served folder","Example with the `wordpress` service of the official image, whose web folder is `\u002Fvar\u002Fwww\u002Fhtml` (adapt the service and path to your stack): `docker compose exec wordpress sh -c 'echo \"\u003C?php echo PHP_VERSION, \\\" \\\", PHP_SAPI;\" > \u002Fvar\u002Fwww\u002Fhtml\u002Fv-check.php'`",{"title":78,"body":79},"Query it over HTTP, then delete it right away","`curl -s https:\u002F\u002Fyour-domain.com\u002Fv-check.php` then `docker compose exec wordpress rm \u002Fvar\u002Fwww\u002Fhtml\u002Fv-check.php`. The answer gives the version followed by the SAPI. Compare it with the fixed versions: 8.5.12, 8.4.27, 8.3.36 or 8.2.35 depending on the branch. A lower number for your branch means the fix is not there.",{"title":81,"body":82},"Check the container's FPM binary","`docker exec \u003Ccontainer> php-fpm -v` prints the version and SAPI of that specific container's FPM binary. With an Apache image, the HTTP request from the previous step is enough: `mod_php` is loaded by Apache.",{"title":84,"body":85},"Do not trust docker compose run","`docker compose run` creates a fresh container from the local image. It can report the fixed version while the site's container has not moved. Always check the container that receives traffic.",{"type":39,"title":87,"body":88},"Floating tags and pinned tags: what moves by itself","A branch tag such as `php:8.3-fpm` advances at the next `pull`: it then points to the fixed version. An exact tag such as `php:8.3.36-fpm` stays on its version, and a digest reference (`@sha256:…`) never moves. The `docker image pull` documentation is explicit: with a digest, Docker fetches no rebuild, security fixes included, until you change the digest yourself.\n\nThe fixed tags of the official `php` image reached Docker Hub during the day and evening of October 21, 2026 (UTC), for the FPM variants of branches 8.5, 8.4, 8.3 and 8.2. The official WordPress images `php8.3-fpm`, `php8.4-fpm` and `php8.3-apache` were republished on October 22, 2026 in the early morning (UTC), and Nextcloud's the same day. An image pulled before those moments is therefore the old one, even with an identical name. Check these dates on each tag's page. Branch 8.2 gets its fix but reaches end of life on December 31, 2026: plan its replacement.",{"type":90,"title":91,"headers":92,"rows":96},"comparison","Which notation moves, which stays frozen",[93,94,95],"In your compose file or Dockerfile","Moves at the next pull?","To get the fixed PHP",[97,101,105,108,112,115,119,123],[98,99,100],"`php:8.3-fpm`","Yes, the tag is republished","`pull` or `build --pull`, then recreate the container",[102,103,104],"`php:8.3.36-fpm`","No, exact version","Already fixed; change it by hand at the next fix",[106,103,107],"`php:8.3.\u003Cn>-fpm` with n below 36","Move to a fixed tag, rebuild, recreate",[109,110,111],"`wordpress:php8.3-fpm`","Yes, the maintainers republish it","`pull`, then recreate the service",[113,114,111],"`wordpress:\u003Cx.y>-php8.3-fpm`","Yes for PHP: the maintainers republish it",[116,117,118],"`php:8.3-fpm@sha256:…`","Never","Replace the digest with that of a fixed image",[120,121,122],"`FROM php:8.3-fpm` in your Dockerfile","Only if you build with `--pull`","`build --pull`, then recreate the container",[124,125,126],"`image: myregistry\u002Fapp:latest` (your image)","No, it is your last build","Rebuild, republish, then pull and recreate",{"type":39,"title":128,"body":129},"Custom image: the sequence and what each option changes","For an image built in-house from `FROM php:8.3-fpm`, the sequence takes three commands: `docker compose build --pull --no-cache`, then `docker compose up -d --force-recreate`, then a check of the served version. Each answers a specific trap.\n\n`--pull` is the option that changes the PHP version: it tells Docker to look for a newer version of the base image instead of reusing the server's. Without it, the `FROM` is resolved with the local copy, and the build succeeds with the old interpreter, without a single message.\n\n`--no-cache` replays every layer, including `apt-get` and `composer install`, which also renews system libraries and dependencies. It is not needed to change PHP, because when the base image changes the following layers are rebuilt on their own. It is useful when a cached layer freezes a package you want renewed.\n\n`--force-recreate` recreates containers even if Compose considers their configuration and image unchanged. That removes the doubt about what is running.\n\nRebuilding your images at each fix is a schedule to keep, not a one-off action. On a VPS with root access, that schedule is yours, and \u003Ca href=\"\u002Fblog\u002Fdemarrer-avec-docker-vps\">our guide to installing Docker on a VPS\u003C\u002Fa> lays the groundwork.",{"type":53,"title":131,"steps":132},"Rebuild and recreate a custom image",[133,136,139,142],{"title":134,"body":135},"Check that the base tag is fixed","Open your base tag's page on Docker Hub and check that it was published from October 21, 2026. If your `FROM` targets an older exact version, change it first.",{"title":137,"body":138},"Rebuild while pulling the base","`docker compose build --pull --no-cache`. Note the version before the operation with the test file, to have a before and an after.",{"title":140,"body":141},"Recreate the containers","`docker compose up -d --force-recreate`. A single command can also chain the three steps: `docker compose up -d --build --pull always`. Recreate every service that uses the image: web, queue worker, scheduler.",{"title":143,"body":144},"Prove the result","Run the test file again, then compare the ID given by `docker inspect --format '{{.Image}}' \u003Ccontainer>` with that of `docker image ls`. The old and new images can carry the same name: only the ID and the HTTP answer are proof.",{"type":39,"title":146,"body":147},"Official WordPress and Nextcloud: PHP comes from the tag","A WordPress tag combines a WordPress version, a PHP version and a variant, for example `php8.3-apache` or `php8.3-fpm`. The PHP branch is chosen by the tag name. Changing the WordPress version, or letting automatic updates act in the data volume, does not touch that branch. To get the fixed PHP, re-pull the tag with `docker compose pull`, then recreate the service. The Apache variant is the default one, and it loads PHP as `mod_php`: the PHP project considers it the most exposed, with an exploit demonstrated before any application code runs. Treat it as a priority.\n\nNextcloud follows the same principle, in two variants: `apache` ships a full Apache, `fpm` needs a web server in front of it. The image documentation describes the update as a replacement: pull the image, throw away the old container, start the new one. Nextcloud's code and your data live in the `\u002Fvar\u002Fwww\u002Fhtml` volume, which recreating the container does not erase. See also \u003Ca href=\"\u002Fblog\u002Fheberger-wordpress\">our WordPress on VPS guide\u003C\u002Fa> and \u003Ca href=\"\u002Fblog\u002Fheberger-nextcloud\">the Nextcloud one\u003C\u002Fa>.",{"type":39,"title":149,"body":150},"Laravel Octane and FrankenPHP: the engine is in the image","With Octane and FrankenPHP there is no PHP-FPM: the application server embeds the interpreter. The official FrankenPHP images are built on the official PHP images, and their tag combines the FrankenPHP version, the PHP version and the system, in the form `dunglas\u002Ffrankenphp:\u003Cversion>-php8.4-trixie`. The project rebuilds them at each release and, every day at 4 am UTC, if new official PHP images exist. Your `FROM dunglas\u002Ffrankenphp` only gets the fix if you rebuild your image with `--pull`.\n\nThe trap specific to Octane is the worker. Octane boots the application once and keeps it in memory: `php artisan octane:reload` gracefully restarts the workers to load the deployed code. It is the right move after a code deployment, but it does not replace the interpreter, which remains that of the running image. The same goes for a `kill -USR2` or a PHP-FPM reload run in the old container: they restart the same files, those of the old image. To change PHP, recreate the container, including those of queue workers and the scheduler. See \u003Ca href=\"\u002Fblog\u002Fdeployer-laravel-vps-octane\">our Laravel Octane on VPS guide\u003C\u002Fa>.",{"type":43,"title":152,"items":153},"Infrastructure traps that replay the old image",[154,155,156,157,158,159],"**CI build cache** — a restored layer cache can replay the `FROM` layer. Add `--pull` to the CI build command, or invalidate the cache for that step.","**Private registry or mirror** — if your servers pull from an internal registry that copies images by hand or on a schedule, check that it copied the tag. Otherwise `pull` answers `Image is up to date` while the maintainers have republished.","**Portainer stack or orchestration tool** — updating a stack does not always re-pull the image. Tick the re-pull option before redeploying if your tool offers one.","**`pull_policy: missing`** — it is Compose's default without a `build` section: it only pulls if the image is absent from the server. Only the `latest` tag is pulled in every case. Use `always`, or `daily` and `weekly` to check the registry at a fixed interval.","**A forgotten service** — web, worker, scheduler and `cli` container built from separate Dockerfiles each have their own base: fix them all.","**An orphan container** — a forgotten `docker run` or another Compose project may still answer on a port. List everything running with `docker ps`.",{"type":90,"title":161,"headers":162,"rows":166},"Troubleshooting: what you see, what it means",[163,164,165],"What you notice","Probable cause","Remedy",[167,171,175,179,183],[168,169,170],"`pull` prints `Status: Image is up to date` but the version stays old","The tag has not been republished yet, or you pull an exact version or a digest","Compare with the tag date on Docker Hub, then move to a fixed tag",[172,173,174],"`up -d` changes nothing after a pull","The existing container was not recreated","`docker compose up -d --force-recreate`, then compare image IDs",[176,177,178],"The build finishes in a few seconds, with the base already cached","`--pull` is missing: the server's base is reused","`docker compose build --pull`, with `--no-cache` if system packages must also be renewed",[180,181,182],"`docker compose run` reports the fixed version, the site answers the old one","`run` creates a fresh container, the web service was not recreated","Check the container that receives traffic over HTTP, then recreate it",[184,185,186],"The version is right but a worker behaves as before","A queue or Octane worker still runs in an old container","Recreate every container that uses the image, not only the web service",{"type":39,"title":188,"body":189},"The official documentation","The sources: \u003Ca href=\"https:\u002F\u002Fwww.php.net\u002Farchive\u002F2026.php\">PHP security and release announcements\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcli\u002Fdocker\u002Fcompose\u002Fup\u002F\">docker compose up\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcli\u002Fdocker\u002Fcompose\u002Fbuild\u002F\">docker compose build\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcompose-file\u002Fservices\u002F#pull_policy\">the pull_policy attribute\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fcli\u002Fdocker\u002Fimage\u002Fpull\u002F\">docker image pull\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fhub.docker.com\u002F_\u002Fphp\">the php image\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fhub.docker.com\u002F_\u002Fwordpress\">the wordpress image\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fnextcloud\u002Fdocker\">the Nextcloud image\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Ffrankenphp.dev\u002Fdocs\u002Fdocker\u002F\">FrankenPHP with Docker\u003C\u002Fa> and \u003Ca href=\"https:\u002F\u002Flaravel.com\u002Fdocs\u002F12.x\u002Foctane\">Laravel Octane\u003C\u002Fa>.","A VPS where you own your images and their schedule","On a ServOrbit.com VPS, you get root access and a dedicated IPv4: your Docker images, their tags and the timing of each rebuild are yours. A VPS administration option also exists; its terms are described on the offer page.","Discover VPS","\u002Fvps-cloud",[195,212,232],{"id":196,"slug":197,"slugs":198,"title":202,"excerpt":203,"readTime":204,"views":205,"isPinned":19,"publishedAt":206,"updatedAt":207,"category":208,"categories":209,"featuredImage":30,"bgImage":31,"posterImage":211,"relatedSolution":30},489,"php2shell-cve-2026-109618-109619-patch-php",{"fr":199,"en":197,"ar":200,"es":201},"php2shell-cve-2026-109618-109619-mettre-a-jour-php","php2shell-cve-2026-109618-109619-تحديث-php","php2shell-cve-2026-109618-109619-actualizar-php","PHP2Shell: patch CVE-2026-109618 and CVE-2026-109619","PHP2Shell: two critical PHP flaws exploitable without an account. Patched versions, update commands per system and temporary mitigations.",9,1,"2026-10-22T00:00:00+00:00","2026-10-22T01:57:44+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[210],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fphp2shell-cve-2026-109618-109619-mettre-a-jour-php-poster.svg",{"id":213,"slug":214,"slugs":215,"title":219,"excerpt":220,"readTime":221,"views":18,"isPinned":19,"publishedAt":222,"updatedAt":21,"category":223,"categories":228,"featuredImage":30,"bgImage":31,"posterImage":230,"relatedSolution":231},73,"host-wordpress-on-your-own-vps",{"fr":216,"en":214,"ar":217,"es":218},"heberger-wordpress","استضافة-wordpress-على-خادم-vps-الخاص-بك","alojar-wordpress-en-un-vps","Host WordPress on your own VPS","Host WordPress on your VPS for maximum performance and control: Docker, MariaDB, caching, reverse proxy and SSL.",7,"2026-04-08T00:00:00+00:00",{"id":221,"name":224,"slug":225,"color":226,"icon":227},"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[229],{"id":221,"name":224,"slug":225,"color":226,"icon":227},"\u002Fblog\u002Fcovers\u002Fheberger-wordpress-poster.svg",{"categorySlug":225,"appSlug":35},{"id":233,"slug":234,"slugs":235,"title":238,"excerpt":239,"readTime":240,"views":18,"isPinned":19,"publishedAt":241,"updatedAt":242,"category":243,"categories":249,"featuredImage":30,"bgImage":31,"posterImage":251,"relatedSolution":30},436,"laravel-octane-vps-frankenphp-docker-traefik",{"fr":236,"en":234,"ar":237,"es":234},"deployer-laravel-vps-octane","laravel-octane-على-vps-frankenphp-docker-traefik","Laravel Octane on VPS: FrankenPHP, Docker and Traefik","Move from PHP-FPM to Laravel Octane with FrankenPHP in Docker Compose behind Traefik, understand request lifecycle changes and avoid memory leaks in production.",11,"2026-10-12T00:00:00+00:00","2026-10-13T14:10:28+00:00",{"id":244,"name":245,"slug":246,"color":247,"icon":248},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[250],{"id":244,"name":245,"slug":246,"color":247,"icon":248},"\u002Fblog\u002Fcovers\u002Fdeployer-laravel-vps-octane-poster.svg",1792799409637]