Missing Multi-Stage Build
Convert the single-stage Dockerfile to a multi-stage build and add a HEALTHCHECK.
The Problem
Docker builds your image in a single stage. That means the final image contains Composer, its dependencies, and any build tooling — none of which belong in production.
Right now your image is unnecessarily large. Multi-stage builds let you use a heavy builder image to install dependencies, then throw it away and copy only the artifacts you need into a lean runtime image.
What You Need to Fix
Load this challenge:
php artisan challenge:start docker-missing-multistageA Dockerfile is copied into your project root. It works — but it installs Composer directly into the final image. This is the broken pattern you need to fix.
Open the Dockerfile. You'll see three problems:
- No builder stage — there's only one
FROMblock, and it installs everything into the same image that runs PHP-FPM in production - Composer binary copied into the runtime image — the line
COPY --from=composer:2 /usr/bin/composer /usr/bin/composerputs Composer where it doesn't belong - No HEALTHCHECK — Docker has no way to know whether PHP-FPM is actually accepting requests, only that the process is alive
What You Must Do
Convert the Dockerfile to a proper two-stage build:
Stage 1: builder
Use FROM composer:2 AS builder as your first stage. This image has PHP and Composer pre-installed. Your job in this stage is only to install dependencies:
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-interaction --optimize-autoloaderStage 2: runtime
Start fresh with FROM php:8.2-fpm-alpine. Install extensions. Then copy the vendor directory from the builder — not Composer itself:
COPY --from=builder /app/vendor ./vendorRemove COPY --from=composer:2 /usr/bin/composer /usr/bin/composer entirely — that line installs the Composer binary into your production image, which is what you're trying to avoid.
Add a HEALTHCHECK
Before the CMD, add a HEALTHCHECK that tests PHP-FPM's configuration:
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD php-fpm -t || exit 1Hints
- The first
FROMshould beFROM composer:2 AS builderand sets up a temporary build environment - The second
FROMisFROM php:8.2-fpm-alpine— this is the image that actually runs in production COPY --from=builder /app/vendor ./vendorpulls the installedvendor/directory from the builder stage into the runtime imageHEALTHCHECKgoes after theEXPOSEinstruction, beforeCMD
Verify
php artisan challenge:verifyAll five checks must pass.