As a seasoned web developer, I've spent countless hours wrestling with local development environments. From conflicting dependencies to "it works on my machine" woes, the struggle is real. But what if I told you there's a better way? A way to ensure consistency, portability, and isolation for your projects? Today, we're diving deep into how to set up a PHP development environment with Docker, transforming your workflow from a battlefield into a well-oiled machine. Forget XAMPP or MAMP; Docker is the modern developer's superpower for PHP.
Why Docker is a Game Changer for PHP Development
Traditional PHP development often involves installing PHP, a web server like Apache or Nginx, and a database like MySQL directly on your host machine. This approach quickly becomes problematic. Different projects often require different PHP versions, specific extensions, or unique database configurations, leading to inevitable dependency conflicts.
Docker elegantly solves this by containerizing each service. With Docker, each component (PHP, Nginx, MySQL) runs in its own isolated container, providing significant advantages:
- Consistency: Your development environment precisely mirrors production, drastically reducing "works on my machine" issues.
- Isolation: Each project can have its own specific PHP version and dependencies without affecting other projects on your machine.
- Portability: Your entire environment is defined in code (
Dockerfileanddocker-compose.yml), making it incredibly easy to share with team members or deploy across different machines. - Efficiency: Spin up and tear down complex environments in seconds, allowing you to focus more on coding and less on configuration.
This level of isolation and consistency is crucial, especially when working on projects that might eventually scale into Mastering Microservices for Modern Web Development. Docker provides the foundational environment for robust development practices.

Prerequisites: Getting Started with Docker
Before we jump into the setup, you'll need Docker installed on your system. Docker Desktop is the easiest way to get started for Windows, macOS, and Linux. Head over to the official Docker website and download the appropriate installer for your operating system.
Once installed, open your terminal or command prompt and verify Docker is running correctly by typing:
docker --version
docker compose version
You should see version numbers for both Docker and Docker Compose (which is often bundled with Docker Desktop).
Project Structure and Core Files
Let's define a simple project structure for our PHP application. Create a new directory, say my-php-app, and inside it, we'll place our configuration files and application code.
my-php-app/
├── public/
│ └── index.php
├── docker-compose.yml
├── Dockerfile
└── .env
The public/ directory will hold our PHP application files, with index.php being our entry point. The other files are for Docker configuration.
Step 1: The Dockerfile for PHP-FPM
First, we need a Dockerfile to build our custom PHP-FPM image. This file defines how our PHP container will be constructed, including the PHP version, necessary extensions, and configurations.
Create a file named Dockerfile in your project root with the following content:
FROM php:8.2-fpm-alpine
WORKDIR /var/www/html
RUN apk update && apk add --no-cache \
curl \
mysql-client \
git \
build-base \
autoconf \
nginx
RUN docker-php-ext-install pdo_mysql opcache
COPY . /var/www/html
RUN chown -R www-data:www-data /var/www/html
EXPOSE 9000
CMD ["php-fpm"]
This Dockerfile uses an Alpine-based PHP 8.2 FPM image for a smaller footprint. It installs common utilities and the pdo_mysql extension (crucial for database interaction) and sets up permissions. We're explicitly defining how to set up a php development environment with docker by building a custom PHP image here.
Step 2: Defining Services with docker-compose.yml
Next, we'll use docker-compose.yml to orchestrate our multiple services: Nginx (our web server), PHP-FPM (our custom PHP service), and MySQL (our database). This file describes the entire stack and how the services interact.
Create a file named docker-compose.yml in your project root:
version: '3.8'
services:
nginx:
image: nginx:stable-alpine
container_name: my-php-nginx
ports:
- "80:80"
volumes:
- ./public:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
networks:
- my-php-network
php:
build:
context: .
dockerfile: Dockerfile
container_name: my-php-fpm
volumes:
- ./public:/var/www/html
networks:
- my-php-network
mysql:
image: mysql:8.0
container_name: my-php-mysql
env_file:
- ./.env
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- dbdata:/var/lib/mysql
ports:
- "3306:3306" # Optional: Expose for local access if needed
networks:
- my-php-network
networks:
my-php-network:
driver: bridge
volumes:
dbdata:
This configuration defines three services: nginx, php, and mysql. They all share a custom network (`my-php-network`) for seamless internal communication. Nginx is exposed on port 80, and MySQL on 3306 (optional, for local tools). The PHP service builds from our custom Dockerfile.
Step 3: Nginx Configuration
We need a simple Nginx configuration to serve our PHP files and pass PHP requests to our PHP-FPM container. Create a new directory named `nginx` in your project root, and inside it, create `default.conf`:




