Docker for PHP Developers — Containerizing Your Laravel Application
January 2, 2026 · 10 min read
Introduction
Docker has transformed how PHP applications are developed, tested, and deployed. Instead of wrestling with platform-specific setups — Homebrew on macOS, apt on Ubuntu, XAMPP on Windows — you define your entire stack in code and run it consistently everywhere. For Laravel developers, Docker provides a reproducible environment with Nginx, PHP-FPM, MySQL, and Redis that matches production. This guide walks through a production-grade Docker setup from scratch.
Docker vs Vagrant vs Homestead
Laravel Homestead is a Vagrant box that provisions a full Ubuntu VM. It works well but is heavy — a VM reserves gigabytes of RAM and CPU upfront. Docker containers, by contrast, share the host kernel and start in seconds. Vagrant is better when you need a full OS environment with systemd services; Docker excels for lightweight, isolated service stacks. For most Laravel projects, Docker provides the best balance of performance and fidelity.
Dockerfile for PHP 8.x
The Dockerfile is the blueprint for your PHP-FPM image. It installs PHP with the extensions Laravel needs — PDO, Mbstring, BCMath, GD, Redis, and others.
FROM php:8.3-fpm
RUN apt-get update && apt-get install -y \
libpng-dev libjpeg-dev libfreetype6-dev zip unzip git curl \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql bcmath gd
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
COPY . .
RUN composer install --optimize-autoloader --no-dev
RUN chown -R www-data:www-data storage bootstrap/cache
EXPOSE 9000
CMD ["php-fpm"]
docker-compose.yml with Multi-Service Stack
Docker Compose orchestrates multiple containers. Below is a four-service stack: Nginx as the web server, PHP-FPM to process PHP, MySQL for the database, and Redis for caching.
version: '3.9'
services:
app:
build: .
volumes:
- .:/var/www
networks:
- laravel
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- .:/var/www
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- laravel
mysql:
image: mysql:8.0
environment:
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: root
volumes:
- db_data:/var/lib/mysql
networks:
- laravel
redis:
image: redis:alpine
networks:
- laravel
volumes:
db_data:
networks:
laravel:
Running Artisan Commands in Containers
Once the stack is running (docker compose up -d), you interact with the application container to run Artisan commands. Use docker compose exec to run commands inside the running service:
docker compose exec app php artisan migrate
docker compose exec app php artisan cache:clear
docker compose exec app php artisan tinker
Laravel Sail as an Alternative
Laravel Sail is a lightweight command-line tool for interacting with a default Docker development environment. It ships with Laravel 11 and provides convenient commands like ./vendor/bin/sail up and sail artisan migrate. Sail wraps docker-compose and is perfect for individual developers. However, for custom stacks — multiple PHP versions, custom Nginx configs, or complex service dependencies — writing your own Docker setup gives you full control.
Multi-Stage Builds for Production
In production, you want a lean image without Composer, dev dependencies, or build tools. Multi-stage builds let you compile assets and install dependencies in a build stage, then copy only the runtime artifacts to the final image. The result is an image that is often 80% smaller — critical for faster deployments and lower bandwidth costs.
Common Pitfalls
Permission issues top the list — the www-data user inside the container must own storage/ and bootstrap/cache/ for Laravel to write logs and cached views. Cache invalidation is another: OPcache and route caches live inside the container and reset on rebuild. Use Redis for shared cache across container restarts. Performance can suffer if you mount the entire project as a bind mount on macOS (filesystem overhead); use Docker's :cached or :delegated volume flags to mitigate this.
Conclusion
Docker brings consistency and portability to PHP development. By defining your infrastructure as code, you eliminate "it works on my machine" problems and streamline onboarding for new team members. Start with the Dockerfile and compose file above, then customize for your specific stack. Laravel Sail is a great starting point, but understanding the underlying Docker setup empowers you to build production-ready, scalable environments.
Need help containerizing your Laravel application? Our team designs Docker workflows for development and production that scale from solo developers to enterprise teams.
Get in Touch