eloquage/docker-php
Docker PHP offers a streamlined containerized PHP setup for Laravel and other PHP applications. It bundles sensible Docker configuration for PHP-FPM, web server, database, and cache services, making local development and deployment easier with minimal setup and straightforward customization.
This package scaffolds a Docker-based PHP development environment for Laravel and (per the 1.1.x line) registers a Docker-backed dashboard via a Saloon HTTP client. The fastest path from zero to running app:
composer require --dev eloquage/docker-php. If you have anything pinning Saloon 3, resolve that first (see Gotchas).docker-compose.yml, helper scripts) and config: php artisan vendor:publish --tag=docker-php (or the package's install command if it registers one).docker-compose.yml and .env.docker (or the env keys the compose file expects) before the first docker compose up -d --build.Where to look first: the published docker/ directory and docker-compose.yml at the project root — these are the files you edit day-to-day. Second, the published config/docker-php.php and the package's route registration: 1.1.1 verifies "16 dashboard routes" on a fresh Laravel 12 app, so if you want the dashboard, check php artisan route:list for the package's route group and confirm auth/middleware before exposing it anywhere non-local.
First use case: bringing a fresh Laravel clone up locally with PHP-FPM + Nginx (or Caddy), MySQL/Postgres, Redis, and a mail catcher, without touching the host's PHP version. Copy .env.example to .env, set DB_HOST/REDIS_HOST to the compose service names, then docker compose up -d.
1.1.1 is a patch on top of 1.1.0, but it carries two effectively breaking constraints: the PHP 8.3 floor and the Saloon 4 major bump. If your lockfile or CI images are on PHP 8.2 or Saloon 3, treat this upgrade as a planned change, not a composer update.
Keep published files in version control and treat them as app code. Once published, the Dockerfiles and compose file are yours. Republishing on upgrade will overwrite local tweaks — diff first, merge selectively.
Layer environment-specific overrides. Keep a base docker-compose.yml from the package and add docker-compose.override.yml for local-only concerns (Xdebug, bind-mount performance options, extra ports). Use docker-compose.ci.yml for CI, where you typically want no bind mounts, a pre-built image, and opcache enabled.
Customize PHP extensions in the Dockerfile, not at runtime. Add docker-php-ext-install/pecl install lines in your app's Dockerfile stage. If the package ships a base image, extend it (FROM eloquage/php:...) rather than editing the base. Note that base images you consume must now be built on PHP 8.3+ to match the package's constraint.
Run tooling through the container. Standardize on docker compose exec app php artisan ..., docker compose exec app composer ..., and docker compose run --rm node npm .... A short Makefile or shell aliases (art, composer, pest) removes the friction that pushes people back to host PHP.
Wire queue workers and the scheduler as separate services. Add queue (same image, php artisan queue:work) and scheduler (php artisan schedule:work in dev; cron or a supervisor in prod-like setups) services instead of overloading the app container. This matches how the app will run in production and surfaces failures early.
Toggle Xdebug via env, not by rebuilding. Use an XDEBUG_MODE env var and a startup script or ini include so off/debug/coverage can be switched per-run. In CI, force XDEBUG_MODE=off so coverage runs don't silently slow the suite.
Share the database service across worktrees. Give the DB volume a fixed name in compose so multiple checkouts can reuse one MySQL instance (different databases), or isolate with a project-name prefix — pick one deliberately.
In CI, build once and reuse. Build the app image in a prior job (on a PHP 8.3 base), push to the registry, then have test jobs pull and run composer install --no-dev-style steps inside it. Avoid rebuilding per matrix entry.
Isolate the Saloon client from your own. If you already use Saloon for third-party APIs, treat the package's connector as a separate integration: don't share a global connector/middleware stack or a shared cache plugin config between your API clients and the Docker client. Keep the Docker client's base URL and token in its own config key so credential handling and rate limits stay independent.
Treat the dashboard as an internal tool. The 16 dashboard routes registered on a fresh install are convenience surface for local/ops use. Put them behind auth middleware and a non-public route prefix (or APP_ENV guard). Prefer a read-only or status-only wiring in shared environments rather than exposing container management.
.platform.php in composer.json, and any docker/ base image you own in the same change. Symptoms of a half-done upgrade: Composer resolves the package but your app image still runs 8.2 and composer install in-container fails the platform check.saloonphp/saloon requirement.withoutDeprecationHandlers or run with failOnDeprecation, scope it to your own suite.storage/ and bootstrap/cache/ as root is the most common post-install breakage. Pass UID/GID build args (or use a user-mapping entrypoint) and chown the writable directories. Symptoms: "Permission denied" on logs, or Laravel unable to write compiled views.localhost inside a container is the container. Set DB_HOST=mysql, REDIS_HOST=redis, MAIL_HOST=mailhog in the container env. Host-side php artisan and container-side commands need different .env values; don't share one file blindly.host.docker.internal is not available on Linux by default. Add extra_hosts: ["host.docker.internal:host-gateway"] if Xdebug or a host service needs to be reached.vendor/ and node_modules/ over a bind mount are slow. Use named volumes for those directories, or enable VirtioFS/:cached delegation. Don't bind-mount the whole repo into a production-like image.php artisan config:clear (and config:cache only in prod-like flows). A stale bootstrap/cache/config.php will ignore your new DB_HOST.XDEBUG_MODE is explicitly off in CI and for routine local runs; enable debug/coverage only for the task at hand.3306, 6379, 80/443, and 8025 frequently clash with host services or other projects. Parameterize host ports via .env (e.g. FORWARD_DB_PORT) rather than hardcoding.depends_on does not wait for readiness. MySQL accepts connections after the container is "up". Add healthchecks plus depends_on: condition: service_healthy, or an entrypoint wait loop, or migrations will fail intermittently on first boot..env out of the image; pass secrets at runtime or via compose env_file. Add .dockerignore entries for .env, vendor/, node_modules/, and .git. This matters more now that the package ships a Docker client — a leaked Docker socket or token is host-level access.How can I help you explore Laravel packages today?