Docker for PHP Developers: Complete Setup Guide

Stop fighting with XAMPP and WAMP. This guide shows PHP developers how to set up Docker for Laravel and CodeIgniter projects with MySQL, Redis, and hot reloading - from zero to production-ready.

If you have ever heard "it works on my machine" from a teammate, Docker is the cure. It packages your entire development environment - PHP, MySQL, Redis, Nginx - into containers that run identically everywhere.

This guide is written for PHP developers who have never used Docker. By the end, you will have a working Laravel or CodeIgniter project running in containers with hot reloading, database persistence, and a setup that mirrors production.

Why Docker for PHP?

Traditional PHP setups (XAMPP, WAMP, MAMP, Laragon) have real problems:

  • Everyone on the team has a slightly different PHP version or extension set
  • Switching between PHP 8.1 and 8.3 for different projects is painful
  • MySQL version mismatches cause migration failures
  • Setting up the same environment on a new developer laptop takes hours
  • Your local environment never matches production

Docker solves all of these. One docker compose up command and every developer has an identical environment in minutes.

Installing Docker

Install Docker Desktop from docker.com. It works on Windows, macOS, and Linux. On Windows, make sure WSL 2 is enabled for best performance.

Verify the installation:

docker --version
docker compose version

Project Structure

Add these files to your PHP project root:

your-project/
    docker/
        nginx/
            default.conf
        php/
            Dockerfile
    docker-compose.yml
    .dockerignore

Step 1: PHP Dockerfile

Create docker/php/Dockerfile:

FROM php:8.3-fpm

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git curl zip unzip libpng-dev libonig-dev \
    libxml2-dev libzip-dev libfreetype6-dev \
    libjpeg62-turbo-dev libwebp-dev \
    && docker-php-ext-configure gd \
        --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install \
        pdo_mysql mbstring exif pcntl bcmath gd zip \
    && pecl install redis && docker-php-ext-enable redis \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Set working directory
WORKDIR /var/www/html

# Copy project files
COPY . .

# Install dependencies
RUN composer install --no-dev --optimize-autoloader

EXPOSE 9000
CMD ["php-fpm"]

This gives you PHP 8.3 with all the extensions Laravel and CodeIgniter need: PDO MySQL, GD for images, Redis, ZIP, and Composer.

Step 2: Nginx Configuration

Create docker/nginx/default.conf:

server {
    listen 80;
    server_name localhost;
    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;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

Step 3: Docker Compose

Create docker-compose.yml in your project root:

version: "3.8"

services:
  php:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    volumes:
      - .:/var/www/html
    depends_on:
      - mysql
      - redis
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - .:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
    networks:
      - app-network

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: app_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_password
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - app-network

  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    networks:
      - app-network

volumes:
  mysql-data:

networks:
  app-network:

Step 4: Start Everything

# Build and start all containers
docker compose up -d

# Check running containers
docker compose ps

# View logs
docker compose logs -f php

Visit http://localhost:8080 and your PHP app is running.

Essential Docker Commands for PHP Developers

# Run artisan commands (Laravel)
docker compose exec php php artisan migrate
docker compose exec php php artisan tinker

# Run Composer
docker compose exec php composer install
docker compose exec php composer require package-name

# Access MySQL CLI
docker compose exec mysql mysql -u app_user -p app_db

# Rebuild after Dockerfile changes
docker compose up -d --build

# Stop everything
docker compose down

# Stop and remove all data (fresh start)
docker compose down -v

Hot Reloading in Development

The volumes directive in docker-compose.yml mounts your local code into the container. When you edit a PHP file on your machine, the change is immediately reflected in the container. No restart needed - this is how hot reloading works with Docker.

For frontend assets (if running npm/Vite), add a Node container:

  node:
    image: node:20-alpine
    volumes:
      - .:/var/www/html
    working_dir: /var/www/html
    command: npm run dev
    ports:
      - "5173:5173"
    networks:
      - app-network

Environment-Specific Configuration

Update your Laravel .env to use Docker service names:

DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=app_db
DB_USERNAME=app_user
DB_PASSWORD=app_password

REDIS_HOST=redis
REDIS_PORT=6379

CACHE_DRIVER=redis
SESSION_DRIVER=redis

Docker automatically resolves service names to container IPs within the same network. So mysql in your env file points to the MySQL container.

Common Issues and Fixes

Permission Errors on Linux

Add your user ID to the Dockerfile: RUN usermod -u 1000 www-data. This ensures file permissions match between your host and the container.

MySQL Connection Refused

MySQL takes a few seconds to initialize. Use depends_on with a health check, or simply wait 10 seconds after docker compose up before running migrations.

Slow Performance on Windows

Use WSL 2 backend and keep your project files inside the WSL filesystem (not on /mnt/c/). File operations through the Windows filesystem are significantly slower.

From Development to Production

The beauty of Docker is that the same containers run in production. The main differences:

  • Do not mount volumes - copy files into the image instead
  • Use composer install --no-dev to exclude dev dependencies
  • Add health checks to your compose file
  • Use Docker secrets or environment variables for credentials
  • Add a reverse proxy (Traefik or Nginx) for SSL termination

Summary

Docker eliminates the "works on my machine" problem for PHP teams. With a Dockerfile, Nginx config, and docker-compose.yml, every developer gets an identical environment in one command. Start with the basic setup in this guide, then add services as your project needs them. Once you experience the reliability of containerized development, you will never go back to XAMPP.

Share This Article

Tags

Docker PHP Laravel DevOps Nginx MySQL Containers
Harjit Singh Sekhon
About the Author
Harjit Singh Sekhon
Project Manager

Harjit is a SaaS developer, CRM/ERP and e-commerce solutions architect with 7+ years of experience and 15+ full-stack web applications delivered with clean code and on-time delivery. He specializes in project architecture, database and system design, and the complete flow of operations from planning to deployment. At Logic Providers, Harjit has built multi-tenant SaaS platforms, e-commerce stores, admin dashboards, and mobile apps for global clients. He has implemented AI-based chatbots trained on platform-specific data, payroll management systems with role-based access and approval workflows, customer loyalty and rewards engines with points tracking and segmentation, and REST API backends for mobile and third-party integrations including UPS, USPS, Stripe, PayPal, QuickBooks Online, HubSpot, and 3PL Central. Before writing a line of code, he documents what already exists, reads the current logic first, then makes changes incrementally so nothing breaks unexpectedly. Harjit works cleanly alongside existing teams and lead developers without causing conflicts, bringing clear communication and no black boxes to every project.

Connect on LinkedIn
Docker for PHP Developers: Complete Setup Guide
Written by
Harjit Singh Sekhon
Harjit Singh Sekhon
LinkedIn
Published
April 17, 2026
Read Time
10 min read
Category
Development
Tags
Docker PHP Laravel DevOps Nginx MySQL Containers
Start Your Project

Related Articles

Have a Project in Mind?

Let's discuss how we can help bring your vision to life.