DEV Community

Zouhair Ghaidoud
Zouhair Ghaidoud

Posted on

A Practical Guide to Docker for Laravel Developers

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

Enter fullscreen mode Exit fullscreen mode

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.

  1. Install Sail in an existing Laravel project:
composer require laravel/sail --dev
php artisan sail:install

Enter fullscreen mode Exit fullscreen mode

Select your preferred services (e.g., mysql, redis, mailpit).

  1. Start your containers:
./vendor/bin/sail up -d

Enter fullscreen mode Exit fullscreen mode
  1. Run commands inside the environment:
./vendor/bin/sail artisan migrate
./vendor/bin/sail composer require laravel/sanctum

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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:

Enter fullscreen mode Exit fullscreen mode

4. Connecting and Running

  1. Update your .env file: Inside Docker networks, containers communicate using their service names as hostnames. Change DB_HOST from 127.0.0.1 to db:
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=secret_password

Enter fullscreen mode Exit fullscreen mode
  1. Build and start the services:
docker compose up -d --build

Enter fullscreen mode Exit fullscreen mode
  1. Run your migrations:
docker compose exec app php artisan migrate

Enter fullscreen mode Exit fullscreen mode

Open http://localhost:8000 in your browser. Your Laravel application is now fully running inside isolated, reproducible containers.

Top comments (0)