Skip to main content

Docker Compose Structure

The docker-compose.yml file defines the entire multi-container application. It’s located in the root of the project and orchestrates four services.

Complete Configuration

services:
  postgres:
    image: postgres:16-alpine
    container_name: laravel_postgres
    environment:
      POSTGRES_DB: laravel
      POSTGRES_USER: laravel
      POSTGRES_PASSWORD: secret
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - laravel_network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U laravel -d laravel"]
      interval: 5s
      timeout: 3s
      retries: 20

  app:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
      args:
        UID: "1000"
        GID: "1000"
    container_name: laravel_app
    working_dir: /var/www/html
    volumes:
      - ./:/var/www/html
    environment:
      DB_CONNECTION: pgsql
      DB_HOST: postgres
      DB_PORT: 5432
      DB_DATABASE: laravel
      DB_USERNAME: laravel
      DB_PASSWORD: secret
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - laravel_network

  nginx:
    image: nginx:1.27-alpine
    container_name: laravel_nginx
    ports:
      - "8000:80"
    volumes:
      - ./:/var/www/html:ro
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app
    networks:
      - laravel_network

  node:
    image: node:22-alpine
    container_name: laravel_node
    working_dir: /var/www/html
    user: "0:0"
    volumes:
      - ./:/var/www/html
      - node_modules:/var/www/html/node_modules
    ports:
      - "5173:5173"
    command: sh -lc "chown -R 1000:1000 /var/www/html/node_modules && npm ci || npm i && npm run dev -- --host 0.0.0.0 --port 5173 --strictPort"

volumes:
  postgres_data:
  node_modules:

networks:
  laravel_network:
    driver: bridge

Service Configuration Breakdown

PostgreSQL Service

VariableValueDescription
POSTGRES_DBlaravelDefault database name
POSTGRES_USERlaravelDatabase user
POSTGRES_PASSWORDsecretDatabase password
Change POSTGRES_PASSWORD in production environments. Never commit production credentials to version control.

Laravel App Service

build:
  context: .
  dockerfile: docker/php/Dockerfile
  args:
    UID: "1000"
    GID: "1000"
  • Context: Build context is the project root
  • Dockerfile: Custom PHP-FPM image at docker/php/Dockerfile
  • Build Args: User/Group IDs for permission alignment with host
The UID/GID match the host user, preventing permission issues with mounted volumes.

Nginx Service

ports:
  - "8000:80"
Maps container port 80 to host port 8000. Access the application at http://localhost:8000.
You can change the host port (left side) if 8000 is already in use: "3000:80"

Node Service

command: sh -lc "chown -R 1000:1000 /var/www/html/node_modules && npm ci || npm i && npm run dev -- --host 0.0.0.0 --port 5173 --strictPort"
Startup sequence:
  1. Fix permissions on node_modules directory
  2. Install dependencies (npm ci or fallback to npm i)
  3. Start Vite dev server on all interfaces
The --host 0.0.0.0 flag allows access from the host machine.

Volume Configuration

Named Volumes

volumes:
  postgres_data:
  node_modules:

postgres_data

Persists PostgreSQL data files across container lifecycles. Data survives docker-compose down.

node_modules

Caches Node.js dependencies. Improves build performance and prevents host/container conflicts.

Volume Management Commands

# List volumes
docker volume ls

# Inspect a volume
docker volume inspect macuin_postgres_data

# Remove volumes (data loss!)
docker volume rm macuin_postgres_data

# Remove all unused volumes
docker volume prune
Removing the postgres_data volume will delete your database. Always backup data before removing volumes.

Network Configuration

networks:
  laravel_network:
    driver: bridge
The bridge network driver creates an isolated network for service-to-service communication.

Network Features

  • DNS Resolution: Services can reference each other by name
  • Isolation: Separated from host network and other Docker networks
  • Port Publishing: Only explicitly mapped ports are accessible from host

Dockerfile Configuration

PHP Application Dockerfile

FROM php:8.3-fpm

ARG UID=1000
ARG GID=1000

RUN apt-get update && apt-get install -y \
    git curl unzip zip \
    libpq-dev \
 && docker-php-ext-install pdo pdo_pgsql \
 && rm -rf /var/lib/apt/lists/*

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

RUN groupadd -g ${GID} appuser \
 && useradd -m -u ${UID} -g ${GID} appuser

WORKDIR /var/www/html
USER appuser
FROM php:8.3-fpm
Official PHP 8.3 with FastCGI Process Manager for production-ready performance.

Docker Ignore Configuration

The .dockerignore file excludes unnecessary files from the build context:
.dockerignore
.git
node_modules
vendor
storage/logs
storage/framework/cache
storage/framework/sessions
storage/framework/views
.env
Excluding these files reduces build context size and improves build speed.

Customizing Configuration

Change Database Credentials

  1. Update environment variables in docker-compose.yml:
postgres:
  environment:
    POSTGRES_DB: myapp
    POSTGRES_USER: myuser
    POSTGRES_PASSWORD: strongpassword
  1. Update corresponding variables in the app service:
app:
  environment:
    DB_DATABASE: myapp
    DB_USERNAME: myuser
    DB_PASSWORD: strongpassword

Change Host Ports

Modify the left side of port mappings:
nginx:
  ports:
    - "3000:80"  # Changed from 8000 to 3000

node:
  ports:
    - "5174:5173"  # Changed from 5173 to 5174

Customize User IDs

If your host user has a different UID/GID:
app:
  build:
    args:
      UID: "1001"  # Your actual UID
      GID: "1001"  # Your actual GID
Find your UID/GID with: id -u and id -g

Add Environment Variables

Extend the app service environment:
app:
  environment:
    DB_CONNECTION: pgsql
    # ... existing vars ...
    MAIL_MAILER: smtp
    MAIL_HOST: mailhog
    MAIL_PORT: 1025

Next Steps

Services

Learn how to manage individual services

Overview

Review the architecture overview

Build docs developers (and LLMs) love