PHP 8: Modern PHP Development · Performance and Deployment

Docker for PHP Applications

Build lean, secure production images with multi-stage Dockerfiles.

Use the official php:8.4-fpm (or -cli) images, install only the extensions you need with docker-php-ext-install, install Composer dependencies in a build stage, and copy the optimized vendor/ into a slim runtime image. Run as a non-root user, use the production php.ini, enable OPcache, and pair the FPM container with Nginx (or use FrankenPHP/RoadRunner as an all-in-one application server).

FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --optimize-autoloader

FROM php:8.4-fpm-alpine
RUN docker-php-ext-install pdo_pgsql opcache \
 && mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/opcache.ini $PHP_INI_DIR/conf.d/opcache.ini
WORKDIR /var/www/app
COPY --from=vendor /app/vendor ./vendor
COPY . .
RUN chown -R www-data:www-data storage
USER www-data

Common pitfalls

  • Shipping dev dependencies and Composer in the runtime image.
  • Running as root.
  • Rebuilding vendor on every code change because COPY order breaks layer caching.

Key points

  • Multi-stage: Composer stage → slim runtime
  • Production php.ini + OPcache
  • Non-root user

Further reading: Official PHP Docker images

Practice questions

Why copy composer.json/lock before the rest of the source?

Answer

Docker caches layers; dependencies are reinstalled only when those files change, not on every code edit, speeding up builds.

What are FrankenPHP and RoadRunner?

Answer

Application servers that can keep PHP workers alive between requests (worker mode), serving HTTP directly. They reduce bootstrap overhead but require care with state leaking between requests.

Open in the app to mark lessons complete, take notes and track your progress.