Docker has become a standard tool for local development: it isolates environments, makes projects reproducible, and eliminates the classic “works on my machine” problem. In this post, I’ll walk you through a basic Docker workflow using a simple PHP + MySQL + Laravel stack.
🎯 What We Want to Achieve
- A PHP container (e.g., PHP 8.2) to run Laravel
- A MySQL container
- An optional but recommended Nginx container
- A single
docker-compose.yml
to orchestrate everything
- A minimal set of commands for daily development
📦 Project Structure
A typical structure looks like this:
project/
├─ src/ # Laravel project
├─ docker/
│ ├─ php/
│ │ └─ Dockerfile
│ └─ nginx/
│ └─ default.conf
└─ docker-compose.yml
⚙️ PHP Dockerfile
docker/php/Dockerfile
:
FROM php:8.2-fpm
RUN apt-get update && apt-get install -y \
git zip unzip curl libpq-dev libzip-dev \
&& docker-php-ext-install pdo pdo_mysql zip
COPY –from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
This gives you a minimal PHP-FPM image with Composer and required extensions.
🗄️ MySQL Configuration
Inside
docker-compose.yml
:
services:
mysql:
image: mysql:8.0
container_name: mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
🌐 Nginx Configuration
docker/nginx/default.conf
:
server {
listen 80;
root /var/www/html/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
🧩 docker-compose.yml
version: '3.8'
services:
php:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: php
volumes:
- ./src:/var/www/html
depends_on:
- mysql
nginx:
image: nginx:latest
container_name: nginx
ports:
- "8080:80"
volumes:
- ./src:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
🚀 Starting the Project
1. Create a Laravel project
docker compose run --rm php composer create-project laravel/laravel .
2. Start all containers
docker compose up -d
3. Check in the browser
http://localhost:8080
🔄 Basic Daily Workflow
1. Install dependencies
docker compose exec php composer install
2. Run migrations
docker compose exec php php artisan migrate
3. Run Artisan commands
docker compose exec php php artisan tinker
4. View logs
docker compose logs -f php docker compose logs -f nginx docker compose logs -f mysql
5. Restart a service
docker compose restart php
🧹 Useful Tips
- Don’t install PHP, MySQL, or Nginx locally — Docker replaces all of them.
- Keep configs in separate files (
docker/php/Dockerfile
,
docker/nginx/default.conf
) for easier maintenance.
- Use a volume for MySQL to avoid losing data.
- Run Composer inside the container, not on your host machine.
🎉 Conclusion
This basic stack is a great starting point for any PHP/Laravel project. It’s simple, transparent, and easy to extend: Redis, Horizon, Queue Workers, Mailhog — all of these can be added with just a few lines in
docker-compose.yml
.








