How to Set Up a Local Laravel Development Environment with Docker
When setting up a Laravel project, one of the biggest challenges is keeping your local environment consistent with production. PHP versions, Composer, database configs β they can vary from machine to machine and cause frustrating bugs.
Docker solves this problem by allowing you to package your environment in containers. In this post, Iβll show you how to set up a local Laravel development environment using Docker and Docker Compose.
Weβll use a custom Laravel-ready PHP image that I maintain on Docker Hub under jcadima/laravel-php, along with MySQL and Nginx. Once you follow these steps, youβll have a reproducible environment you can spin up anywhere.
Why Choose Docker for Laravel Development?
Before diving into the setup, let's understand why Docker is an excellent choice for Laravel development:
Docker ensures your development environment matches production exactly, eliminating environment-related bugs and deployment surprises.
New team members can get up and running with a single command instead of spending hours installing and configuring dependencies.
Each project runs in its own containers, preventing conflicts between different PHP versions or extensions across projects.
Your entire environment configuration is stored in version-controlled files, making it easy to track changes and roll back if needed.
Prerequisites
Before we begin, make sure you have the following installed on your system:
- Docker Desktop (Windows/macOS) or Docker Engine (Linux)
- Docker Compose (usually included with Docker Desktop)
- Git (for version control)
- A code editor (Vim, VS Code, PhpStorm, etc.)
docker --version
docker-compose --version
Use the Laravel Docker Image
For this setup, we'll use a specially crafted Docker image that includes everything Laravel needs out of the box.
The image comes pre-configured with:
PHP 8.2 with FPM (FastCGI Process Manager)
- Optimized for production-like performance
- Better resource management than Apache mod_php
- Seamless integration with Nginx
Composer Pre-installed
- Latest stable version
- Optimized for faster dependency resolution
- Includes all necessary certificates
Essential PHP Extensions
- pdo_mysql - Database connectivity
- mbstring - Multibyte string handling
- bcmath - Arbitrary precision mathematics
- gd - Image processing capabilities
- zip - Archive handling
- intl - Internationalization support
- opcache - Performance optimization
Security Features
- Non-root user configuration
- Proper file permissions
- Minimal attack surface
You can find it here: π jcadima/laravel-php on Docker Hub
Setting Up Your Project Structure
Let's start by creating a well-organized project structure that separates your Laravel application from Docker configuration files:
mkdir my-laravel-project
cd my-laravel-project
Your project directory should follow this structure:
my-laravel-project/
βββ src/ # Your Laravel application
β βββ app/
β βββ config/
β βββ public/
β βββ .env
β βββ ... (other Laravel files)
βββ docker-compose.yml # Main Docker Compose configuration
βββ docker-compose/
β βββ nginx/
β βββ http.conf # Custom Nginx configuration
βββ .gitignore # Git ignore rules
βββ README.md # Project documentation
This structure keeps your Laravel code separate from Docker configuration, making it easier to manage and deploy.
Creating the Docker Compose Configuration
Hereβs an example docker-compose.yml to get started:
version: "3.9"
services:
app:
image: jcadima/laravel-php:8.2
container_name: laravel-app
restart: unless-stopped
working_dir: /var/www/laravel
volumes:
- ./src:/var/www/laravel
networks:
- laravel-net
nginx:
image: nginx:1.23-alpine
container_name: laravel-nginx
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./src:/var/www/laravel
- ./docker-compose/nginx/http.conf:/etc/nginx/conf.d/default.conf
networks:
- laravel-net
db:
image: mysql:8
container_name: laravel-db
restart: unless-stopped
env_file: ./src/.env
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: "${DB_DATABASE}"
MYSQL_USER: "${DB_USERNAME}"
MYSQL_PASSWORD: "${DB_PASSWORD}"
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
volumes:
- db-data:/var/lib/mysql
networks:
- laravel-net
volumes:
db-data:
networks:
laravel-net:
driver: bridge
Nginx Configuration for Laravel
The example above references a file docker-compose/nginx/http.conf.
Create the directory structure for Nginx configuration:
mkdir -p docker-compose/nginx
Create docker-compose/nginx/http.conf with this Laravel-optimized configuration:
server {
listen 80;
index index.php index.html;
server_name localhost;
root /var/www/laravel/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
}
Setting Up Your Laravel Environment
If you don't have a Laravel project yet, you can create one using the containerized environment:
Option 1: Create a New Laravel Project
# Create the src directory
mkdir src
# Create a new Laravel project using Docker
docker run --rm \
-v $(pwd)/src:/app \
composer \
create-project --prefer-dist laravel/laravel .
Option 2: Use an Existing Project
If you have an existing Laravel project, simply move or copy it into the src directory.
Configure Your Laravel Environment
Update your src/.env file with the following database configuration:
APP_NAME="Laravel Docker App"
APP_ENV=local
APP_KEY=base64:your-app-key-here
APP_DEBUG=true
APP_URL=http://localhost:8080
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=db # <- important, this is the service name of your database container (not localhost)
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=redis
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=redis
SESSION_LIFETIME=120
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=hello@example.com
MAIL_FROM_NAME="${APP_NAME}"
Starting Your Development Environment
Now that everything is configured, let's start the development environment:
# Start all containers in detached mode
docker compose up -d
# View the status of all containers
docker compose ps
# Watch the logs (optional)
docker compose logs -f
Accessing Your Application
Once all containers are running, you can access:
- Laravel Application: http://localhost:8080
- MySQL Database: 127.0.0.1:3306 (use your preferred MySQL client)
Essential Docker Commands for Daily Development
Here are the most useful commands you'll need for day-to-day development:
# Start the environment
docker compose up -d
# Stop the environment
docker compose down
# Restart a specific service
docker compose restart app
# View container status
docker compose ps
Additional Docker Container functions (Add it to your .bashrc or .zshrc)
dinspect β Quickly check container status
function dinspect() {
docker inspect $1 | grep Status
}
Purpose: Shows the current status (running, exited, etc.) of a Docker container.
Usage:
dinspect laravel-app
Output might be something like:
"Status": "running",
dlogs β Tail container logs
function dlogs() {
docker logs -f $1
}
Purpose: Stream logs from a container in real-time.
Usage:
dlogs laravel-app
Shows logs like Artisan output, errors, or any console messages.
-f means βfollowβ, so new logs appear automatically.
dnetwork β Get container IP
function dnetwork() {
docker inspect $1 | grep IP
}
Purpose: Quickly find the containerβs IP address inside Docker.
Usage:
dnetwork mysql-db
Useful if you need to connect another container to this one or debug networking issues.
dmysql β Connect to MySQL inside a container
# $1: container name
# $2: database user
function dmysql() {
docker exec -it $1 mysql -u $2 -p
}
Purpose: Open an interactive MySQL session inside a container.
Usage:
dmysql mysql-db root
Prompts for the password, then lets you run SQL queries inside the container.
Saves you from typing the long docker exec -it mysql-db mysql -u root -p every time.
dbash β Get a shell inside a container
function dbash() {
docker exec -it $1 bash
}
Purpose: Opens a bash shell inside a running container for direct interaction.
Usage:
dbash laravel-app
You can now run commands as if you were inside the container, e.g., ls, php artisan, or composer install.
Troubleshooting Common Issues
Port Conflicts
If ports 8080, 3306, or 6379 are already in use on your system, modify the port mappings in docker-compose.yml
Database Persistence
The database data is stored in a named volume (db-data), so your data persists even when containers are recreated.
You now have a fully functional, professional Laravel development environment running on Docker. This setup provides consistency across different machines, easy onboarding for team members, and a solid foundation for building Laravel applications.
The containerized approach eliminates the "works on my machine" problem and gives you confidence that your development environment closely mirrors production.