If you are a Laravel developer, you are probably used to local development stacks like Laragon, Valet, or Herd. While those work well on a single machine, issues crop up the moment you collaborate with a team, switch OS environments, or prepare your project for a production server: "It works on my machine" syndrome.
Here is a straightforward guide to understanding Docker and using it to run your Laravel applications.
1. What is Docker? The Core Mental Model
Think of a Docker container as a lightweight, isolated virtual box that packages your application along with its dependencies—PHP, extensions, Nginx, and databases. Because everything is defined in code, it runs identically on any system.
To understand Docker, you only need three core concepts:
- Dockerfile: The blueprint or recipe. A plain text file defining the base operating system, packages, and PHP extensions your application needs.
- Image: The compiled, read-only snapshot built from your Dockerfile.
- Container: The running instance of an Image. You can start, stop, and destroy containers without affecting the underlying image.
2. Essential Docker Commands
These cover roughly 90% of your day-to-day work:
# Run a container in detached mode (-d) and map port 8080 on your host to port 80 inside the container (-p) docker run -d -p 8080:80 --name my-web-server nginx # List all currently running containers docker ps # List all containers (running and stopped) docker ps -a # Stop and remove a container docker stop my-web-server docker rm my-web-server # List downloaded local images docker images 3. Running Laravel with Docker: Two Approaches
When containerizing Laravel, you have two primary options: Laravel Sail (ideal for rapid local development) and a Custom Dockerfile + Docker Compose setup (ideal for production parity and granular control).
Option A: Laravel Sail (The Quick Path)
Laravel Sail is Laravel’s official, pre-configured Docker development environment.
- Install Sail in an existing Laravel project:
composer require laravel/sail --dev php artisan sail:install Select your preferred services (e.g., mysql, redis, mailpit).
- Start your containers:
./vendor/bin/sail up -d - Run commands inside the environment:
./vendor/bin/sail artisan migrate ./vendor/bin/sail composer require laravel/sanctum Option B: Custom Docker Setup (Full Control)
If you want complete control over your stack or need an architecture that transitions directly into production, set up your own multi-container environment using Docker Compose.
Place the following three files in the root directory of your Laravel application:
1. Dockerfile (PHP 8.3-FPM + Extensions)
FROM php:8.3-fpm-alpine # Install system dependencies & PHP build tools RUN apk add --no-cache \ git \ curl \ libpng-dev \ libonig-dev \ libxml2-dev \ zip \ unzip \ mysql-client # Install required PHP extensions RUN docker-php-ext-install pdo pdo_mysql mbstring exif pcntl bcmath gd # Install Composer directly from its official image COPY --from=composer:latest /usr/bin/composer /usr/bin/composer WORKDIR /var/www EXPOSE 9000 CMD ["php-fpm"] 2. nginx.conf (Web Server Configuration)
server { listen 80; index index.php index.html; root /var/www/public; 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; } } 3. docker-compose.yml (Orchestrating PHP, Nginx, and MySQL)
services: app: build: context: . dockerfile: Dockerfile container_name: laravel-app restart: unless-stopped working_dir: /var/www volumes: - ./:/var/www networks: - laravel-net web: image: nginx:alpine container_name: laravel-web restart: unless-stopped ports: - "8000:80" volumes: - ./:/var/www - ./nginx.conf:/etc/nginx/conf.d/default.conf depends_on: - app networks: - laravel-net db: image: mysql:8.0 container_name: laravel-db restart: unless-stopped environment: MYSQL_DATABASE: laravel_db MYSQL_USER: laravel_user MYSQL_PASSWORD: secret_password MYSQL_ROOT_PASSWORD: root_password ports: - "3306:3306" volumes: - db_data:/var/lib/mysql networks: - laravel-net networks: laravel-net: driver: bridge volumes: db_data: 4. Connecting and Running
- Update your
.envfile: Inside Docker networks, containers communicate using their service names as hostnames. ChangeDB_HOSTfrom127.0.0.1todb:
DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=laravel_db DB_USERNAME=laravel_user DB_PASSWORD=secret_password - Build and start the services:
docker compose up -d --build - Run your migrations:
docker compose exec app php artisan migrate Open http://localhost:8000 in your browser. Your Laravel application is now fully running inside isolated, reproducible containers.

