PHP cookbook · Beginner

Set up a PHP dev environment with Docker Compose

Give every developer the same PHP, database and Redis versions with one command.

Approach

Define PHP-FPM, Nginx, PostgreSQL/MySQL and Redis in compose.yaml, mount the source code for live editing, keep data in named volumes, and pass configuration via environment variables. Add Xdebug only in the dev image.

Solution

# compose.yaml
services:
  php:
    build: { context: ., dockerfile: docker/php/Dockerfile, target: dev }
    volumes: [".:/var/www/app"]
    environment:
      DB_DSN: "pgsql:host=db;dbname=app"
      DB_USER: app
      DB_PASSWORD: secret
      REDIS_HOST: redis
    depends_on:
      db: { condition: service_healthy }
  nginx:
    image: nginx:1.27-alpine
    ports: ["8080:80"]
    volumes:
      - ".:/var/www/app:ro"
      - "./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro"
    depends_on: [php]
  db:
    image: postgres:17-alpine
    environment: { POSTGRES_DB: app, POSTGRES_USER: app, POSTGRES_PASSWORD: secret }
    volumes: ["dbdata:/var/lib/postgresql/data"]
    healthcheck: { test: ["CMD", "pg_isready", "-U", "app"], interval: 5s, retries: 10 }
  redis:
    image: redis:7-alpine
volumes:
  dbdata:
# docker/php/Dockerfile
FROM php:8.4-fpm-alpine AS base
RUN docker-php-ext-install pdo_pgsql opcache
FROM base AS dev
RUN apk add --no-cache $PHPIZE_DEPS linux-headers && pecl install xdebug redis && docker-php-ext-enable xdebug redis

Pitfalls

  • Using latest tags so environments drift.
  • Committing real credentials in compose files.
  • Slow bind mounts on macOS for vendor/ — consider a named volume for it.

Variations

  • Laravel Sail or DDEV provide preconfigured setups.
  • FrankenPHP image as an all-in-one server.

Further reading: Docker Compose documentation

Reference: https://docs.docker.com/compose/

More PHP recipes