mwguerra/docker-local

Complete Docker development environment for Laravel - PHP 8.4, MySQL 9.1, PostgreSQL 17, Redis 8, Traefik 3.6

Installs: 8

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 0

Language:Shell

pkg:composer/mwguerra/docker-local

0.1.2 2026-01-01 16:48 UTC

This package is auto-updated.

Last update: 2026-01-06 07:44:06 UTC


README

Complete Docker development environment for Laravel with a powerful CLI.

Packagist Version PHP Version License

Global Composer Package — Install once, use everywhere. No per-project Docker configuration needed.

Quick Install

For experienced developers — get up and running in 60 seconds:

# Install globally via Composer
composer global require mwguerra/docker-local

# Add to PATH (add this line to ~/.bashrc or ~/.zshrc for persistence)
export PATH="$HOME/.composer/vendor/bin:$PATH"

# Initialize the environment
docker-local init

# Create your first Laravel project
docker-local make:laravel my-app

# Open in browser (https://my-app.test)
docker-local open

Need prerequisites first? See Installation for platform-specific setup guides.

Features

  • PHP 8.4 with Xdebug 3.4, FFmpeg, and all Laravel extensions
  • MySQL 9.1 and PostgreSQL 17 with pgvector (AI embeddings)
  • Redis 8 for cache, sessions, and queues
  • MinIO S3-compatible object storage
  • Traefik 3.6 reverse proxy with automatic SSL
  • Mailpit for email testing
  • RTMP Server (optional) for live streaming with HLS
  • Whisper AI (optional) for audio transcription
  • Node.js 20 (optional) standalone container for asset builds
  • 50+ CLI commands for rapid development
  • Multi-project support with automatic isolation
  • Cross-platform - Linux, macOS, and Windows (WSL2)

Table of Contents

Requirements

All Platforms

Software Minimum Version Check Command
Docker 24.0+ docker --version
Docker Compose 2.20+ docker compose version
PHP 8.2+ php --version
Composer 2.6+ composer --version

System Requirements

  • RAM: 8GB minimum, 16GB recommended
  • Disk: 20GB free space
  • CPU: 64-bit processor with virtualization support

Installation

Linux

Tested on Ubuntu 22.04+, Debian 12+, Fedora 38+, and Arch Linux.

# 1. Install Docker (if not already installed)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker

# 2. Install PHP and Composer (Ubuntu/Debian)
sudo apt update
sudo apt install php8.3 php8.3-{cli,curl,mbstring,xml,zip} unzip
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# 3. Install docker-local
composer global require mwguerra/docker-local

# 4. Add Composer bin to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH="$HOME/.composer/vendor/bin:$PATH"

# 5. Reload shell and run setup
source ~/.bashrc  # or source ~/.zshrc
docker-local init

# 6. (Optional) Configure DNS for *.test domains
sudo "$(which docker-local)" setup:dns

macOS

Tested on macOS 12 (Monterey) and later.

# 1. Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 2. Install Docker Desktop
brew install --cask docker
# Launch Docker Desktop from Applications

# 3. Install PHP and Composer
brew install php composer

# 4. Install docker-local
composer global require mwguerra/docker-local

# 5. Add Composer bin to PATH (add to ~/.zshrc)
export PATH="$HOME/.composer/vendor/bin:$PATH"

# 6. Reload shell and run setup
source ~/.zshrc
docker-local init

# 7. (Optional) Configure DNS for *.test domains
sudo "$(which docker-local)" setup:dns

Windows (WSL2)

Important: docker-local requires WSL2 on Windows. Native Windows is not supported.

Step 1: Install WSL2

# Run in PowerShell as Administrator
wsl --install -d Ubuntu

Restart your computer when prompted.

Step 2: Install Docker Desktop

  1. Download Docker Desktop for Windows
  2. During installation, ensure "Use WSL 2 based engine" is checked
  3. After installation, go to Settings > Resources > WSL Integration
  4. Enable integration with your Ubuntu distribution

Step 3: Install docker-local (in WSL2 Ubuntu)

# Open Ubuntu from Start Menu, then run:

# Install PHP and Composer
sudo apt update
sudo apt install php8.3 php8.3-{cli,curl,mbstring,xml,zip} unzip
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# Install docker-local
composer global require mwguerra/docker-local

# Add to PATH (add to ~/.bashrc)
echo 'export PATH="$HOME/.composer/vendor/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

# Run setup
docker-local init

# (Optional) Configure DNS
sudo "$(which docker-local)" setup:dns

Accessing Projects from Windows

Your WSL2 projects are accessible in Windows Explorer at:

\\wsl$\Ubuntu\home\<username>\projects

Or in VS Code:

# From WSL2 terminal
code ~/projects/my-project

Quick Start

New Project

# Create a new Laravel project (everything is configured automatically)
docker-local make:laravel my-app

# With PostgreSQL instead of MySQL
docker-local make:laravel my-app --postgres

# Navigate to project
cd ~/projects/my-app

# Open in browser (https://my-app.test)
docker-local open

# Run artisan commands
docker-local tinker
docker-local new:model Post -mcr

# View logs
docker-local logs
docker-local logs:laravel

# Stop environment
docker-local down

Existing Project

If you have an existing Laravel project, copy it to ~/projects/ and configure it:

# 1. Copy your project to the projects directory
cp -r /path/to/existing-project ~/projects/my-existing-app

# 2. Navigate to the project
cd ~/projects/my-existing-app

# 3. Create the database
docker-local db:create my_existing_app

# 4. Update your .env file with docker-local settings

Required .env changes for existing projects:

# Database - use Docker service names, not localhost
DB_HOST=mysql                    # or 'postgres' for PostgreSQL
DB_PORT=3306                     # or 5432 for PostgreSQL
DB_DATABASE=my_existing_app      # your project's database name
DB_USERNAME=laravel
DB_PASSWORD=secret

# Redis - use Docker service name
REDIS_HOST=redis
REDIS_PORT=6379

# IMPORTANT: Unique isolation values (prevent conflicts with other projects)
CACHE_PREFIX=my_existing_app_
REDIS_CACHE_DB=0                 # Use different numbers if you have multiple projects
REDIS_SESSION_DB=1               # Project 1: 0-2, Project 2: 3-5, etc.
REDIS_QUEUE_DB=2

# Mail - use Mailpit
MAIL_HOST=mailpit
MAIL_PORT=1025

# MinIO/S3 (optional)
AWS_ENDPOINT=http://minio:9000
AWS_ACCESS_KEY_ID=minio
AWS_SECRET_ACCESS_KEY=minio123
AWS_BUCKET=my_existing_app
AWS_USE_PATH_STYLE_ENDPOINT=true

Quick setup script for existing projects:

# Create database
docker-local db:create my_existing_app

# Create MinIO bucket (optional)
docker exec minio mc mb local/my_existing_app --ignore-existing

# Install dependencies
docker exec -w /var/www/my-existing-app php composer install

# Generate key if needed
docker exec -w /var/www/my-existing-app php php artisan key:generate

# Run migrations
docker exec -w /var/www/my-existing-app php php artisan migrate

# Open in browser
docker-local open my-existing-app

Checklist for existing projects:

  • Project copied to ~/projects/<name>/
  • Database created (docker-local db:create <name>)
  • .env updated with Docker service names (mysql, redis, mailpit)
  • Unique CACHE_PREFIX set (e.g., myproject_)
  • Unique REDIS_*_DB numbers assigned (if running multiple projects)
  • Dependencies installed (composer install)
  • Migrations run (php artisan migrate)
  • Host added to /etc/hosts or dnsmasq configured

CLI Commands

Setup & Diagnostics

docker-local init              # Complete initial setup
docker-local doctor            # Full system health check
docker-local fix [options]     # Diagnose and auto-fix common issues
docker-local config            # View current configuration
docker-local setup:hosts       # Add Docker hostnames to /etc/hosts (sudo)
docker-local setup:dns         # Configure dnsmasq for *.test (sudo)
docker-local update            # Update Docker images

Fix command options:

docker-local fix               # Run all checks, auto-fix what's possible
docker-local fix --dns         # Only check/fix DNS issues
docker-local fix --docker      # Only check/fix Docker daemon
docker-local fix --services    # Only check/fix container services
docker-local fix --hosts       # Only check/fix /etc/hosts
docker-local fix --verbose     # Show detailed diagnostic info
docker-local fix --dry-run     # Show what would be fixed without making changes

The fix command automatically detects and resolves issues like:

  • Docker daemon not running
  • Stopped containers
  • Missing systemd-resolved configuration for *.test DNS
  • Missing dnsmasq configuration
  • /etc/hosts not configured

Environment Management

docker-local up                # Start all containers
docker-local down              # Stop all containers
docker-local restart           # Restart all containers
docker-local status            # Show service status
docker-local logs [service]    # View logs (all or specific service)
docker-local clean             # Clean caches and unused Docker resources

Project Commands

docker-local list              # List all Laravel projects
docker-local make:laravel NAME # Create new Laravel project (MySQL, full isolation)
docker-local make:laravel NAME --postgres  # Create with PostgreSQL + pgvector
docker-local clone REPO        # Clone and setup existing project
docker-local open [name]       # Open project in browser
docker-local open --mail       # Open Mailpit
docker-local open --minio      # Open MinIO Console
docker-local open --traefik    # Open Traefik Dashboard
docker-local ide [editor]      # Open in IDE (code, phpstorm)

make:laravel creates everything automatically:

  • Laravel project via Composer
  • Database (MySQL or PostgreSQL) + testing database
  • MinIO bucket for file storage
  • Unique Redis DB numbers for cache/session/queue
  • Unique cache prefix and Reverb credentials
  • Configured .env with all Docker service connections

Development Commands

docker-local tinker            # Laravel Tinker REPL
docker-local test [options]    # Run tests (supports --coverage, --parallel)
docker-local require PACKAGE   # Install Composer package with suggestions
docker-local logs:laravel      # Tail Laravel logs
docker-local shell             # Open PHP container shell

Artisan Shortcuts

docker-local new:model NAME [-mcr]       # make:model (with migration, controller, resource)
docker-local new:controller NAME [--api] # make:controller
docker-local new:migration NAME          # make:migration
docker-local new:seeder NAME             # make:seeder
docker-local new:factory NAME            # make:factory
docker-local new:request NAME            # make:request
docker-local new:resource NAME           # make:resource
docker-local new:middleware NAME         # make:middleware
docker-local new:event NAME              # make:event
docker-local new:job NAME                # make:job
docker-local new:mail NAME               # make:mail
docker-local new:command NAME            # make:command

Database Commands

docker-local db:mysql          # Open MySQL CLI
docker-local db:postgres       # Open PostgreSQL CLI
docker-local db:redis          # Open Redis CLI
docker-local db:create NAME    # Create new database
docker-local db:dump [name]    # Export database to SQL
docker-local db:restore FILE   # Import SQL file
docker-local db:fresh          # migrate:fresh --seed

Queue Commands

docker-local queue:work        # Start queue worker
docker-local queue:restart     # Restart queue workers
docker-local queue:failed      # List failed jobs
docker-local queue:retry ID    # Retry failed job (or 'all')
docker-local queue:clear       # Clear all queued jobs

Xdebug Commands

docker-local xdebug on         # Enable Xdebug
docker-local xdebug off        # Disable Xdebug (better performance)
docker-local xdebug status     # Show Xdebug status

Startup Commands

Configure docker-local to start automatically when your computer boots:

docker-local startup enable    # Start on OS boot
docker-local startup disable   # Disable startup on boot
docker-local startup status    # Show startup status

Platform-specific behavior:

Platform Method Location
Linux systemd service ~/.config/systemd/user/docker-local.service
macOS LaunchAgent ~/Library/LaunchAgents/com.mwguerra.docker-local.plist
WSL2 bashrc script Entry in ~/.bashrc

Environment Verification

docker-local env:check         # Verify current project .env
docker-local env:check --all   # Audit ALL projects for conflicts
docker-local make:env          # Generate new .env with unique IDs
docker-local update:env        # Update existing .env

Configuration

Configuration is stored in ~/.config/docker-local/config.json:

{
  "version": "2.0.0",
  "projects_path": "~/projects",
  "editor": "code",
  "mysql": {
    "version": "9.1",
    "port": 3306,
    "root_password": "secret",
    "database": "laravel",
    "user": "laravel",
    "password": "secret"
  },
  "postgres": {
    "version": "17",
    "port": 5432,
    "database": "laravel",
    "user": "laravel",
    "password": "secret"
  },
  "redis": {
    "version": "8",
    "port": 6379
  },
  "minio": {
    "api_port": 9000,
    "console_port": 9001,
    "root_user": "minio",
    "root_password": "minio123"
  },
  "mailpit": {
    "smtp_port": 1025,
    "web_port": 8025
  },
  "xdebug": {
    "enabled": true,
    "mode": "develop,debug"
  }
}

Directory Structure

docker-local operates across three locations:

~/.composer/vendor/mwguerra/docker-local/   # Package source (Composer managed)
~/.config/docker-local/                     # User configuration (persistent)
~/projects/                                 # Your Laravel projects

Package Structure (Source Code)

docker-local/
├── bin/
│   └── docker-local              # CLI entry point (symfony/console)
│
├── src/                          # PHP application code
│   ├── Commands/                 # CLI command classes
│   ├── Config/
│   │   ├── ConfigManager.php     # Loads/saves config.json
│   │   ├── ConfigValidator.php   # Validates configuration
│   │   └── PathResolver.php      # Resolves ~ and relative paths
│   ├── DockerLocal.php           # Main application class
│   └── cli-helper.php            # Helper functions for CLI
│
├── lib/
│   └── config.sh                 # Bash helper functions
│
├── scripts/                      # Shell scripts for operations
│   ├── setup.sh                  # Initial environment setup
│   ├── new-project.sh            # Create new Laravel project
│   ├── generate-certs.sh         # SSL certificate generation
│   ├── setup-dns.sh              # Configure dnsmasq for *.test
│   ├── setup-hosts.sh            # Add entries to /etc/hosts
│   ├── create-database.sh        # Create MySQL/PostgreSQL databases
│   ├── make-env.sh               # Generate .env files
│   ├── artisan.sh                # Run artisan commands in container
│   ├── composer.sh               # Run composer in container
│   ├── status.sh                 # Show service status
│   ├── test-connections.sh       # Test database/redis connections
│   ├── add-host.sh               # Add single host entry
│   └── install-cli.sh            # Install CLI globally
│
├── stubs/                        # Templates with placeholders
│   ├── .env.stub                 # Docker environment template
│   ├── laravel.env.stub          # Laravel .env template ({{PROJECT_NAME}})
│   ├── config.json.stub          # Default configuration
│   └── docker-compose.override.yml.stub  # Override template
│
├── templates/
│   ├── install.sh                # Installation script template
│   └── hooks/
│       ├── pre-install.sh        # Runs before project install
│       └── post-install.sh       # Runs after project install
│
├── tests/                        # Pest PHP tests
│   ├── Pest.php                  # Pest configuration
│   ├── Unit/
│   │   ├── ConfigManagerTest.php
│   │   ├── ConfigValidatorTest.php
│   │   └── PathResolverTest.php
│   └── Feature/                  # (Integration tests)
│
├── docs/                         # Extended documentation
│   ├── README.md                 # Docs index
│   ├── architecture.md           # System architecture
│   ├── cli-reference.md          # Full CLI documentation
│   ├── getting-started.md        # Quick start guide
│   ├── services.md               # Service configuration
│   ├── templates.md              # Template system docs
│   └── troubleshooting.md        # Common issues
│
├── resources/docker/             # Alternative/reference Docker files
│   └── docker-compose.yml        # Reference compose file
│
│── Docker Service Configurations ─────────────────────────────
│
├── docker-compose.yml            # Main orchestration file
├── .env.example                  # Docker environment template
├── laravel.env.example           # Laravel .env template (manual use)
│
├── php/                          # PHP-FPM container
│   ├── Dockerfile                # PHP 8.4 with extensions
│   ├── php.ini                   # PHP configuration
│   └── xdebug.ini                # Xdebug settings
│
├── php-ai/                       # PHP + AI tools container
│   ├── Dockerfile                # PHP with Whisper/FFmpeg
│   └── php-ai.ini                # AI container PHP config
│
├── nginx/
│   └── default.conf              # Dynamic multi-project routing
│
├── mysql/
│   ├── my.cnf                    # MySQL configuration
│   └── init/
│       └── 01-create-databases.sql  # Runs on first start
│
├── postgres/
│   └── init/
│       └── 01-create-databases.sql  # Creates DBs + pgvector
│
├── redis/
│   └── redis.conf                # Redis configuration
│
├── traefik/
│   └── dynamic/
│       └── tls.yml               # TLS/SSL configuration
│
├── rtmp/
│   └── nginx-rtmp.conf           # RTMP streaming config
│
│── Root Files ─────────────────────────────────────────────────
│
├── composer.json                 # PHP dependencies
├── composer.lock                 # Locked versions
├── LICENSE                       # MIT License
├── README.md                     # This file
└── PRD.md                        # Product requirements document

User Configuration (~/.config/docker-local/)

Created by docker-local init, persists across updates:

~/.config/docker-local/
├── config.json                   # Your custom settings (ports, paths, etc.)
├── .env                          # Active Docker environment variables
├── certs/                        # SSL certificates (mkcert generated)
│   ├── localhost.pem
│   └── localhost-key.pem
└── docker-compose.override.yml   # Optional: your custom services

Projects Directory (~/projects/)

Each Laravel project is automatically accessible via HTTPS:

~/projects/
├── blog/                         → https://blog.test
│   ├── .env                      # Project-specific Laravel config
│   ├── app/
│   └── ...
├── api/                          → https://api.test
└── shop/                         → https://shop.test

Understanding Environment Files

docker-local uses two separate .env files for different purposes:

File Scope Used By Location
.env.example Docker infrastructure docker-compose.yml ~/.config/docker-local/.env
laravel.env.example Laravel application Laravel framework ~/projects/<project>/.env

.env.example (Docker/Infrastructure)

Controls how Docker containers are built and connected:

PROJECTS_PATH=~/projects       # Where your projects live
MYSQL_PORT=3306               # Port exposed to your host machine
MYSQL_ROOT_PASSWORD=secret    # Container MySQL password
XDEBUG_ENABLED=true           # PHP container configuration

This file is copied to ~/.config/docker-local/.env and read by docker-compose.yml via ${VARIABLE} syntax.

laravel.env.example (Application)

Controls how Laravel connects to services from inside the container:

DB_HOST=mysql                 # Docker service name (NOT localhost!)
DB_PORT=3306                  # Internal container port
REDIS_HOST=redis              # Docker service name
MAIL_HOST=mailpit             # Docker service name

This file is copied to each project's .env (~/projects/my-app/.env) and read by Laravel via env() and config().

Why Both Files Exist

Key insight: The same service has different addresses depending on where you're accessing it from:

Accessing From MySQL Address Why
Your host (TablePlus, DBeaver) localhost:3306 Uses exposed port
Inside PHP container (Laravel) mysql:3306 Uses Docker DNS

The Docker .env configures what ports are exposed to your machine, while the Laravel .env configures how to reach services via Docker's internal network.

Related Files

docker-local/
├── .env.example              # Docker infrastructure template
├── laravel.env.example       # Laravel application template (manual use)
└── stubs/
    ├── .env.stub             # Docker template (for CLI automation)
    └── laravel.env.stub      # Laravel template with {{PLACEHOLDERS}}

The stubs/ versions contain placeholders like {{PROJECT_NAME}} for automated project creation via docker-local make:laravel.

Services

URLs

Service URL
Your Projects https://<project>.test
Traefik Dashboard https://traefik.localhost
Mailpit https://mail.localhost
MinIO Console https://minio.localhost

Ports

Service Port Purpose
Traefik HTTP 80 HTTP (redirects to HTTPS)
Traefik HTTPS 443 HTTPS
MySQL 3306 Database
PostgreSQL 5432 Database
Redis 6379 Cache/Queue
MinIO API 9000 S3 API
MinIO Console 9001 Web UI
Mailpit SMTP 1025 Email
Mailpit Web 8025 Email UI

Default Credentials

Service Username Password
MySQL (root) root secret
MySQL (user) laravel secret
PostgreSQL laravel secret
MinIO minio minio123

All Included Services

All services are now enabled by default. Simply run:

docker-compose up -d

RTMP Server (Live Streaming)

The RTMP server provides live streaming with HLS delivery:

RTMP Configuration:

Endpoint URL
RTMP Ingest rtmp://localhost:1935/live/<stream_key>
HLS Playback http://localhost:8088/hls/<stream_key>.m3u8
HLS (via Traefik) https://stream.localhost/hls/<stream_key>.m3u8
Stats http://localhost:8088/stat

Customizing RTMP:

To add project-specific webhooks (e.g., on_publish callbacks), create a custom config:

# docker-compose.override.yml
services:
  rtmp:
    volumes:
      - ./docker/rtmp/nginx-rtmp.conf:/etc/nginx/nginx.conf:ro
      - ./storage/app/hls:/var/www/hls
      - ./storage/app/recordings:/var/www/recordings

Node.js Container

A dedicated Node.js 20 container for long-running build processes:

# Run npm commands
docker-compose exec node npm install
docker-compose exec node npm run dev

PostgreSQL with pgvector

PostgreSQL 17 now includes the pgvector extension for AI embeddings:

-- Enabled automatically, just use it
CREATE TABLE items (
  id SERIAL PRIMARY KEY,
  embedding vector(1536)
);

-- Similarity search
SELECT * FROM items ORDER BY embedding <-> '[...]' LIMIT 10;

AI/Whisper Transcription

Two options for speech-to-text transcription:

Option 1: Whisper API Container (Recommended)

A dedicated Whisper ASR webservice with OpenAI-compatible HTTP API (using faster-whisper-server):

# API endpoint (internal Docker network)
http://whisper:8000/v1/audio/transcriptions

# API endpoint (from host machine)
http://localhost:9501/v1/audio/transcriptions

# Health check
curl http://localhost:9501/health

Laravel Configuration (.env):

WHISPER_API_URL=http://whisper:8000
WHISPER_TIMEOUT=300
WHISPER_MODEL=base

Example API Call:

curl -X POST http://localhost:9501/v1/audio/transcriptions \
  -F "file=@audio.mp3" \
  -F "model=base" \
  -F "language=en" \
  -F "response_format=json"

Web UI: https://whisper.localhost

Option 2: PHP-AI Container (CLI)

For direct CLI access to Whisper:

# Run transcription via CLI
docker-compose exec php-ai whisper audio.mp3 --model base --language en

# Or from your Laravel app
docker-compose exec php-ai php artisan transcribe:audio path/to/audio.mp3

Whisper Models:

Model Size Memory Speed Accuracy
tiny 39M ~1GB Fastest Lower
base 74M ~1GB Fast Good
small 244M ~2GB Medium Better
medium 769M ~5GB Slow High
large 1550M ~10GB Slowest Best

Configure the model in .env:

WHISPER_MODEL=base
WHISPER_LANGUAGE=en
WHISPER_PORT=9501

Laravel Workers (Horizon, Reverb, Scheduler)

For Laravel-specific services, use the override stub as a template:

# Copy the stub
cp ~/.composer/vendor/mwguerra/docker-local/stubs/docker-compose.override.yml.stub \
   ~/.config/docker-local/docker-compose.override.yml

# Uncomment the services you need and customize

Available templates:

  • Horizon - Queue worker with Laravel Horizon
  • Reverb - WebSocket server for real-time features
  • Scheduler - Cron-like task scheduler
  • Elasticsearch/Meilisearch - Full-text search
  • Soketi - Open-source Pusher alternative

Multi-Project Support

docker-local supports multiple Laravel projects sharing the same Docker services. Each project gets complete automatic isolation to prevent data leakage between projects.

What Gets Created Automatically

When you create a project with docker-local make:laravel myapp, everything is set up automatically:

Creating Laravel project: myapp
Database: MySQL
Redis DBs: cache=0, session=1, queue=2

✓ Project created successfully!
✓ MySQL database 'myapp' created
✓ MySQL database 'myapp_testing' created
✓ MinIO bucket 'myapp' created
✓ .env configured with complete isolation

Isolation settings (multi-project):
  ✓ Database: myapp (MySQL)
  ✓ Redis Cache DB: 0
  ✓ Redis Session DB: 1
  ✓ Redis Queue DB: 2
  ✓ Cache Prefix: myapp_
  ✓ MinIO Bucket: myapp
  ✓ Reverb App ID: 847291

Automatic Isolation Details

Resource How It's Isolated Example Value
Database Unique DB per project myapp, myapp_testing
Redis Cache Separate Redis DB number REDIS_CACHE_DB=0
Redis Session Separate Redis DB number REDIS_SESSION_DB=1
Redis Queue Separate Redis DB number REDIS_QUEUE_DB=2
Cache Prefix Unique prefix per project CACHE_PREFIX=myapp_
MinIO Bucket Separate S3 bucket AWS_BUCKET=myapp
Reverb/WebSockets Unique credentials Random REVERB_APP_ID/KEY/SECRET
Horizon Prefix Unique queue prefix HORIZON_PREFIX=myapp_horizon:

Redis Database Allocation

Redis has 16 databases (0-15). Each project uses 3 databases:

Project Cache DB Session DB Queue DB
1st project 0 1 2
2nd project 3 4 5
3rd project 6 7 8
4th project 9 10 11
5th project 12 13 14

This allows up to 5 fully isolated projects. Beyond that, DB numbers wrap around (with a warning).

PostgreSQL vs MySQL

Both database engines are available. Use the --postgres flag:

# MySQL (default)
docker-local make:laravel myapp

# PostgreSQL with pgvector
docker-local make:laravel myapp --postgres

PostgreSQL projects automatically get these extensions:

  • uuid-ossp - UUID generation
  • pgcrypto - Cryptographic functions
  • vector - pgvector for AI embeddings

Conflict Detection

# Check current project
docker-local env:check

# Audit ALL projects for conflicts
docker-local env:check --all

Example conflict output:

┌─ Cross-Project Conflicts ─────────────────────────────────────────┐
  ⚠ CACHE_PREFIX conflict with 'other-project'
    Both projects use: laravel_cache_

  Why: Cache data will be shared/corrupted between projects
  Fix: Change CACHE_PREFIX in one of the projects' .env files

Running Multiple Projects Simultaneously

All projects can run at the same time without conflicts:

# Terminal 1 - Work on blog
cd ~/projects/blog
docker-local tinker

# Terminal 2 - Work on api
cd ~/projects/api
docker-local test

# Terminal 3 - Work on admin
cd ~/projects/admin
docker-local queue:work

Each project has its own:

  • Database (no shared tables)
  • Cache (no key collisions)
  • Sessions (users stay logged in to their project)
  • Queues (jobs don't mix between projects)
  • File storage (separate MinIO buckets)

Migrating from Project-Specific Docker

If your project has its own Docker configuration, you can migrate to docker-local for a shared, centralized environment.

What docker-local Provides

Service Included Notes
PHP 8.4 FPM Yes With FFmpeg, ImageMagick, 50+ extensions
PostgreSQL 17 Yes With pgvector for AI embeddings
MySQL 9.1 Yes Innovation release
Redis 8 Yes With persistence
MinIO Yes S3-compatible storage
Mailpit Yes Email testing
Nginx Yes Dynamic multi-project routing
Traefik Yes Reverse proxy with SSL
RTMP Server Yes Live streaming with HLS
Whisper API Yes HTTP API for speech-to-text
PHP-AI Yes PHP with Whisper CLI
Node.js 20 Yes Frontend build tooling

What Stays Project-Specific

These should remain in your project's docker-compose.override.yml:

Service Reason
Laravel Horizon Uses app container, just different command
Laravel Reverb WebSocket server specific to your app
Scheduler Cron jobs specific to your app
E2E Testing (Playwright) Test infrastructure is project-specific
Custom AI Models Specialized ML models beyond Whisper

Migration Steps

  1. Copy your project's custom services to an override file:
# Create override in project root
touch ~/projects/your-app/docker-compose.override.yml
  1. Add Laravel-specific services:
# docker-compose.override.yml
services:
  horizon:
    image: php  # Uses docker-local's PHP image
    container_name: your-app-horizon
    working_dir: /var/www/your-app
    volumes:
      - ${PROJECTS_PATH:-../projects}:/var/www:cached
    networks:
      - laravel-dev
    command: php artisan horizon
    depends_on:
      - redis
      - postgres

  reverb:
    image: php
    container_name: your-app-reverb
    working_dir: /var/www/your-app
    volumes:
      - ${PROJECTS_PATH:-../projects}:/var/www:cached
    ports:
      - "8080:8080"
    networks:
      - laravel-dev
    command: php artisan reverb:start --host=0.0.0.0 --port=8080

  scheduler:
    image: php
    container_name: your-app-scheduler
    working_dir: /var/www/your-app
    volumes:
      - ${PROJECTS_PATH:-../projects}:/var/www:cached
    networks:
      - laravel-dev
    command: sh -c "while true; do php artisan schedule:run; sleep 60; done"

networks:
  laravel-dev:
    external: true
  1. Update your .env for docker-local:
# Database (uses docker-local's PostgreSQL)
DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=your_app
DB_USERNAME=laravel
DB_PASSWORD=secret

# Redis
REDIS_HOST=redis
REDIS_PORT=6379

# MinIO
FILESYSTEM_DISK=s3
AWS_ENDPOINT=http://minio:9000
AWS_ACCESS_KEY_ID=minio
AWS_SECRET_ACCESS_KEY=minio123
AWS_BUCKET=your-app
AWS_USE_PATH_STYLE_ENDPOINT=true

# Mail
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
  1. For RTMP/streaming features:
# RTMP is included by default, just start docker-local
cd ~/projects/docker-environment
docker-compose up -d

# Create custom RTMP config with your callbacks (optional)
mkdir -p ~/projects/your-app/docker/rtmp
# Edit nginx-rtmp.conf with on_publish webhooks
  1. Remove old Docker files from your project:
cd ~/projects/your-app
rm -rf docker/
rm docker-compose.yml
rm docker-compose.test.yml
# Keep docker-compose.override.yml for project-specific services
  1. Start using docker-local:
docker-local up
docker-local open your-app

Example: pcast Migration

For a complex streaming application like pcast:

Before (project-specific):

pcast/
├── docker/
│   ├── app/Dockerfile          # Custom PHP with Whisper
│   ├── nginx/                  # nginx configs
│   ├── playwright/             # E2E testing
│   ├── rtmp-tester/            # Test tools
│   └── webrtc-tester/          # Test tools
├── docker-compose.yml          # 12 services
├── docker-compose.test.yml     # Testing
└── docker-compose.testing.yml  # E2E testing

After (docker-local):

pcast/
├── docker/
│   └── rtmp/nginx-rtmp.conf    # Only: Custom RTMP callbacks
├── docker-compose.override.yml # Horizon, Reverb, Scheduler
└── .env                        # Updated for docker-local

Start docker-local (all features included):

cd ~/projects/docker-environment
docker-compose up -d

Benefits:

  • Shared services across all projects
  • Centralized updates and maintenance
  • Consistent development environment
  • Smaller project footprint

IDE Integration

VS Code

  1. Install PHP Debug extension
  2. Create .vscode/launch.json:
{
  "version": "0.2.0",
  "configurations": [{
    "name": "Listen for Xdebug",
    "type": "php",
    "request": "launch",
    "port": 9003,
    "pathMappings": {
      "/var/www/my-project": "${workspaceFolder}"
    }
  }]
}
  1. Start debugging: F5

PhpStorm

  1. Settings → PHP → Debug → Port: 9003
  2. Settings → PHP → Servers:
    • Name: docker
    • Host: localhost, Port: 443
    • Path mappings: /var/www/project~/projects/project
  3. Click "Start Listening for PHP Debug Connections"

Troubleshooting

General Diagnostics

docker-local fix               # Auto-diagnose and fix common issues
docker-local fix --dns -v      # Detailed DNS troubleshooting
docker-local doctor            # Full health check (read-only)
docker-local status            # Service status
docker-local logs              # View all logs
docker-local logs mysql        # View specific service logs

The fix command is the recommended first step when troubleshooting - it automatically diagnoses issues and attempts to fix them where possible.

Common Issues

"Docker daemon is not running"

# Linux
sudo systemctl start docker

# macOS
open -a Docker

# Windows (WSL2)
# Start Docker Desktop from Windows

"Port already in use"

# Find what's using the port
lsof -i :3306  # or :5432, :6379, etc.

# Or change the port in config
# Edit ~/.config/docker-local/config.json

"Permission denied" errors

# Linux: Add user to docker group
sudo usermod -aG docker $USER
newgrp docker

# Or fix project permissions
sudo chown -R $USER:$USER ~/projects

"*.test domains not resolving"

# Quick fix - run the fix command
docker-local fix --dns

# Follow the suggested commands (requires sudo)
sudo "$(which docker-local)" setup:dns

# Manual verification
dig test.test @127.0.0.1     # Should return 127.0.0.1 (dnsmasq working)
ping test.test               # Should resolve to 127.0.0.1 (full system working)

If dnsmasq is working but system DNS isn't:

# Check systemd-resolved configuration (Linux)
cat /etc/systemd/resolved.conf.d/docker-local.conf

# Should contain:
# [Resolve]
# DNS=127.0.0.1#53
# Domains=~test. ~localhost.

SSL Certificate Issues

# Regenerate certificates
docker-local init --certs

# Or manually with mkcert
mkcert -install
mkcert "*.test" "*.localhost"

Cleaning Up

# Clean caches and logs
docker-local clean

# Full cleanup (removes volumes)
docker-local clean --all

# Reset everything
docker-local down
docker system prune -af
docker volume prune -f
docker-local init

Using Local PHP

If you prefer using your local PHP installation with Docker services:

# 1. Configure hostnames
sudo "$(which docker-local)" setup:hosts

# 2. Now use standard PHP commands
cd ~/projects/my-app
php artisan migrate
php artisan serve
composer require laravel/sanctum

The setup:hosts command adds to /etc/hosts:

127.0.0.1 mysql postgres redis minio mailpit

Shell Completion

Bash

# Add to ~/.bashrc
eval "$(docker-local completion bash)"

Zsh

# Add to ~/.zshrc
eval "$(docker-local completion zsh)"

Updating

# Update docker-local CLI
composer global update mwguerra/docker-local

# Update Docker images
docker-local update

# Or combined
docker-local self-update

Extending

Adding Custom Services

Create ~/.config/docker-local/docker-compose.override.yml:

services:
  elasticsearch:
    image: elasticsearch:8.11.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    volumes:
      - elasticsearch_data:/usr/share/elasticsearch/data
    networks:
      - laravel-dev
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"]
      interval: 30s
      timeout: 10s
      retries: 5

volumes:
  elasticsearch_data:

Then restart:

docker-local restart

Custom PHP Configuration

Create ~/.config/docker-local/php/custom.ini:

memory_limit = 512M
upload_max_filesize = 100M
post_max_size = 100M

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

# Clone the repository
git clone https://github.com/mwguerra/docker-local.git
cd docker-local

# Install dependencies
composer install

# Run tests
./vendor/bin/pest

# Run tests with coverage
./vendor/bin/pest --coverage

License

MIT License. See LICENSE for details.

Made with ❤️ for Laravel developers.