Set up a complete Laravel development environment with Docker Compose including PHP-FPM, Nginx, MySQL, and Redis. Reproducible local stacks for every team member.
Introduction
Inconsistent development environments waste hours of debugging time. Docker Compose solves this by defining your entire Laravel stack in a single YAML file that every team member can spin up identically. No more "works on my machine" issues, no conflicting PHP versions, and no manual MySQL installations.
This guide builds a production-like local environment with PHP-FPM, Nginx, MySQL 8, and Redis - all orchestrated through Docker Compose.
Project Structure
project-root/
├── docker/
│ ├── nginx/
│ │ └── default.conf
│ └── php/
│ └── Dockerfile
├── docker-compose.yml
├── .env
└── ... (Laravel files)
The Docker Compose File
version: "3.8"
services:
app:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: laravel-app
volumes:
- .:/var/www/html
networks:
- laravel
depends_on:
- mysql
- redis
nginx:
image: nginx:1.25-alpine
container_name: laravel-nginx
ports:
- "8080:80"
volumes:
- .:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
networks:
- laravel
depends_on:
- app
mysql:
image: mysql:8.0
container_name: laravel-mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
networks:
- laravel
redis:
image: redis:7-alpine
container_name: laravel-redis
ports:
- "6379:6379"
networks:
- laravel
networks:
laravel:
volumes:
mysql-data:
PHP Dockerfile
Create docker/php/Dockerfile:
FROM php:8.3-fpm
RUN apt-get update && apt-get install -y \
git unzip libpng-dev libonig-dev libxml2-dev libzip-dev \
&& docker-php-ext-install pdo_mysql mbstring zip exif pcntl bcmath gd \
&& pecl install redis && docker-php-ext-enable redis
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
Nginx Configuration
Create docker/nginx/default.conf:
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Running the Stack
# Build and start all services
docker compose up -d --build
# Install dependencies
docker compose exec app composer install
# Run migrations
docker compose exec app php artisan migrate
# Verify
curl http://localhost:8080
This approach pairs well with CI/CD pipelines. For teams managing multiple services, check out our guide on WordPress Multisite on Kubernetes. Explore our DevOps as a Service offering to streamline your entire workflow.
Docker Compose gives Laravel teams a consistent, portable development environment that mirrors production. Adding services like Mailhog, MinIO, or Elasticsearch is a matter of appending a few lines to the YAML file. Commit the Docker configuration alongside your application code and every contributor starts from the same baseline.
Or read how we handle it in DevOps as a Service.
Related Articles
Laravel Queue Workers with Supervisor and Redis
Configure Laravel queue workers with Supervisor and Redis for reliable background job processing, automatic restarts, and graceful deployment handling on production servers.
Server & DevOpsDebugging an Airbyte 'All the Defined Primary Keys Are Null' Outage
One of our clients had an Airbyte MySQL to BigQuery pipeline that stopped syncing over a weekend, failing every run with the same error, all the defined primary keys are null. It looked like a data problem. It was not. Here is the two-bug postmortem, including the mid-incident connector upgrade we made that quietly made it worse, and how ruling out suspects one at a time found the real causes.
Next.jsKeep Your Next.js Site Online While You Sleep
Your Next.js app is only as real as its uptime. See how proper monitoring, SLOs, and a calm on-call rhythm turn 'sometimes up' into 'always reliable'.