Two recurring foot-guns in production stacks rolled into one image-level fix: 1. storage/ + bootstrap/cache/ ownership drift. ENABLE_LARAVEL_PERMS was opt-in (default 0) and only chmod'd the top-level dir — so any subdir created later by a different UID (root, nobody, …) stayed un-writable for www-data. Symptom: workkit:db:backup pumping a multi-GB mysqldump into a doomed bash redirect that fails with "Permission denied" only after the pipeline starts. Now default-on (=1), recursive chown + chmod ug+rwX, SGID on dirs so future files inherit the group, and we pre-create the subdirs that ship empty (incl. storage/backups/) so artisan never creates one as the wrong user. 2. mysql client TLS verification against self-signed in-cluster certs. `php artisan db` failed with "TLS/SSL error: self-signed certificate in certificate chain" because modern mysql/mariadb clients auto-enable ssl-verify-server-cert when a password is on argv. Drops a /etc/mysql/conf.d/00-laravel-client.cnf with ssl-verify-server-cert=OFF so the connection still negotiates TLS but skips the chain check — the right tradeoff for a private docker network. Override per-host with MYSQL_CLIENT_VERIFY=ON or by mounting a stricter .cnf. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| config | ||
| docs | ||
| scripts | ||
| .dockerignore | ||
| Dockerfile | ||
| README.md | ||
| docker-bake.hcl | ||
README.md
docker-laravel
A runtime environment for Laravel applications — not Laravel itself.
This image provides everything a Laravel app needs to run: PHP-FPM, Nginx, Composer, Node.js, and a curated set of PHP extensions and system tools. Mount your Laravel project at /var/www/html and you're ready to go.
Built for PHP 7.4 through 8.5, covering Laravel 9 – 13.
Available Tags
By PHP version
| Tag | PHP | Suitable for Laravel |
|---|---|---|
blaxsoftware/laravel:php7.4 |
7.4 | Legacy (< 9) |
blaxsoftware/laravel:php8.0 |
8.0 | 9 |
blaxsoftware/laravel:php8.1 |
8.1 | 9, 10 |
blaxsoftware/laravel:php8.2 |
8.2 | 9, 10, 11, 12 |
blaxsoftware/laravel:php8.3 |
8.3 | 10, 11, 12, 13 |
blaxsoftware/laravel:php8.4 |
8.4 | 11, 12, 13 |
blaxsoftware/laravel:php8.5 |
8.5 | 12, 13 |
blaxsoftware/laravel:latest |
8.4 | (alias for php8.4) |
By Laravel version (recommended PHP)
| Tag | Points to |
|---|---|
blaxsoftware/laravel:laravel9 |
php8.1 |
blaxsoftware/laravel:laravel10 |
php8.3 |
blaxsoftware/laravel:laravel11 |
php8.4 |
blaxsoftware/laravel:laravel12 |
php8.5 |
blaxsoftware/laravel:laravel13 |
php8.5 |
Combo tags (specific PHP + Laravel)
blaxsoftware/laravel:laravel9-php8.0
blaxsoftware/laravel:laravel9-php8.1
blaxsoftware/laravel:laravel9-php8.2
blaxsoftware/laravel:laravel10-php8.1
blaxsoftware/laravel:laravel10-php8.2
blaxsoftware/laravel:laravel10-php8.3
blaxsoftware/laravel:laravel11-php8.2
blaxsoftware/laravel:laravel11-php8.3
blaxsoftware/laravel:laravel11-php8.4
blaxsoftware/laravel:laravel12-php8.2
blaxsoftware/laravel:laravel12-php8.3
blaxsoftware/laravel:laravel12-php8.4
blaxsoftware/laravel:laravel12-php8.5
blaxsoftware/laravel:laravel13-php8.3
blaxsoftware/laravel:laravel13-php8.4
blaxsoftware/laravel:laravel13-php8.5
Quick Start
# Build a single version
docker build --build-arg PHP_VERSION=8.4 -t docker-laravel:php8.4 .
# Build all versions
./scripts/build.sh
# Build only specific PHP versions
./scripts/build.sh 8.4 8.5
# Build all versions with buildx bake
docker buildx bake
# Build only actively-supported PHP versions
docker buildx bake active
plug-n-pray 🙏
Generate a full Docker Compose boilerplate for any Laravel project:
# From your Laravel project root — one-liner:
curl -fsSL https://raw.githubusercontent.com/blax-software/docker-laravel/main/scripts/plug-n-pray.sh | bash
# With options:
./plug-n-pray.sh --php=8.4 --name=my-app --host=my-app.localhost --horizon
# Or via artisan (requires blax-software/laravel-workkit):
php artisan workkit:plug-n-pray
php artisan workkit:plug-n-pray --php=8.5 --horizon --no-mysql
See docs/examples.md for full usage examples.
Usage in docker-compose.yml
services:
app:
image: docker-laravel:php8.4
volumes:
- ./:/var/www/html
ports:
- "80:80"
environment:
ENABLE_QUEUE: "true"
ENABLE_SCHEDULER: "true"
ENABLE_HORIZON: "false"
ENABLE_LARAVEL_PERMS: "1"
Build Args
| Arg | Default | Description |
|---|---|---|
PHP_VERSION |
8.4 |
PHP version (7.4, 8.0 – 8.5) |
NODE_MAJOR |
22 |
Node.js major version |
Runtime Environment Variables
| Variable | Default | Description |
|---|---|---|
ENABLE_QUEUE |
false |
Start artisan queue:work via supervisor |
ENABLE_SCHEDULER |
false |
Start artisan schedule:work via supervisor |
ENABLE_HORIZON |
false |
Start artisan horizon via supervisor |
ENABLE_LARAVEL_PERMS |
1 |
Pre-create + chown -R www-data + chmod ug+rwX (with SGID) on storage/ and bootstrap/cache/ on every boot. Idempotent. Set to 0 to opt out. |
MYSQL_CLIENT_VERIFY |
OFF |
Whether the bundled mysql/mariadb client verifies the server cert chain. Default OFF is right for in-cluster MySQL with a self-signed cert (the connection is still encrypted). Set to ON if you connect to a real public host. |
What's Included
- PHP-FPM with extensions: pdo_mysql, pdo_pgsql, mysqli, mbstring, exif, pcntl, bcmath, gd (freetype + jpeg + webp), sockets, zip, xml, soap, intl, opcache
- PECL: redis, ev, igbinary, imagick (graceful fallback if unavailable for a PHP version)
- OPcache with JIT auto-enabled on PHP 8.0+
- Nginx with headers-more module, optimized for Laravel
- Composer (latest)
- Node.js + npm
- Image optimizers: optipng, pngquant, gifsicle, webp, avif, svgo
- ffmpeg, ghostscript, MySQL client
Architecture
start-container (entrypoint)
└─ supervisord
├─ php-fpm (always)
├─ nginx (always)
├─ queue.conf (if ENABLE_QUEUE=true)
├─ scheduler.conf (if ENABLE_SCHEDULER=true)
└─ horizon.conf (if ENABLE_HORIZON=true)
Optional supervisor configs are generated at runtime in /etc/supervisor/laravel.d/.
Customizing Supervisor Programs
Every supervisor program lives in its own .conf file across three include directories:
| Directory | Purpose | How to customize |
|---|---|---|
/etc/supervisor/conf.d/ |
Core services (php-fpm, nginx) | Mount a replacement file to override |
/etc/supervisor/laravel.d/ |
Queue, scheduler, horizon (auto-generated from ENABLE_* env vars) |
Use env vars, or disable them and mount your own |
/etc/supervisor/custom.d/ |
Empty — for your own programs | Mount a directory or individual files |
Examples:
services:
app:
image: blaxsoftware/laravel:php8.4
volumes:
- ./:/var/www/html
# Override php-fpm config (e.g. change pool settings)
- ./docker/php-fpm.conf:/etc/supervisor/conf.d/php-fpm.conf
# Add custom programs (e.g. reverb, octane, custom workers)
- ./docker/supervisor/:/etc/supervisor/custom.d/
environment:
ENABLE_QUEUE: "true"
To disable a core service (e.g. nginx), mount an override with autostart=false:
; my-nginx-override.conf
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=false