Initial commit: multi-version PHP+Nginx Docker image for Laravel
This commit is contained in:
commit
7ccb8b94fe
|
|
@ -0,0 +1,13 @@
|
|||
.git
|
||||
.github
|
||||
.gitignore
|
||||
*.md
|
||||
!README.md
|
||||
LICENSE
|
||||
docker-bake.hcl
|
||||
scripts/build.sh
|
||||
scripts/publish.sh
|
||||
docker-compose*.yml
|
||||
.env*
|
||||
.idea
|
||||
.vscode
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
# ===========================================================================
|
||||
# docker-laravel — Multi-version PHP + Nginx image for Laravel
|
||||
#
|
||||
# Build args:
|
||||
# PHP_VERSION — 7.4 | 8.0 | 8.1 | 8.2 | 8.3 | 8.4 | 8.5 (default: 8.4)
|
||||
# NODE_MAJOR — Node.js major version (default: 22)
|
||||
# ===========================================================================
|
||||
ARG PHP_VERSION=8.4
|
||||
FROM php:${PHP_VERSION}-fpm
|
||||
|
||||
ARG PHP_VERSION
|
||||
|
||||
LABEL maintainer="docker-laravel"
|
||||
LABEL description="Laravel-optimized PHP-FPM + Nginx image"
|
||||
LABEL php.version="${PHP_VERSION}"
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=UTC
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# System dependencies (single layer)
|
||||
# ---------------------------------------------------------------------------
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gnupg gosu curl wget ca-certificates zip unzip git \
|
||||
supervisor sqlite3 libcap2-bin python3 pkg-config \
|
||||
# GD
|
||||
libfreetype6-dev libjpeg62-turbo-dev libpng-dev libwebp-dev \
|
||||
# PHP extension libs
|
||||
libonig-dev libxml2-dev libzip-dev libicu-dev libcurl4-openssl-dev \
|
||||
# PostgreSQL
|
||||
libpq-dev \
|
||||
# ImageMagick
|
||||
libmagickwand-dev \
|
||||
# Nginx + headers-more module
|
||||
nginx libnginx-mod-http-headers-more-filter \
|
||||
# Database clients
|
||||
default-mysql-client \
|
||||
# Ghostscript (PDF rendering)
|
||||
ghostscript \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PHP extensions
|
||||
# ---------------------------------------------------------------------------
|
||||
# GD configure flags changed between PHP 7.x and 8.0
|
||||
RUN PHP_MAJOR=$(php -r "echo PHP_MAJOR_VERSION;") && \
|
||||
if [ "$PHP_MAJOR" -ge 8 ]; then \
|
||||
docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
|
||||
else \
|
||||
docker-php-ext-configure gd --with-freetype-dir=/usr --with-jpeg-dir=/usr --with-webp-dir=/usr; \
|
||||
fi && \
|
||||
docker-php-ext-install -j$(nproc) \
|
||||
pdo_mysql \
|
||||
pdo_pgsql \
|
||||
mysqli \
|
||||
mbstring \
|
||||
exif \
|
||||
pcntl \
|
||||
bcmath \
|
||||
gd \
|
||||
sockets \
|
||||
zip \
|
||||
xml \
|
||||
soap \
|
||||
intl \
|
||||
opcache
|
||||
|
||||
# PECL extensions (fail gracefully for bleeding-edge PHP)
|
||||
RUN pecl install redis && docker-php-ext-enable redis || echo "NOTICE: redis unavailable for PHP ${PHP_VERSION}"
|
||||
RUN pecl install ev && docker-php-ext-enable ev || echo "NOTICE: ev unavailable for PHP ${PHP_VERSION}"
|
||||
RUN pecl install igbinary && docker-php-ext-enable igbinary || echo "NOTICE: igbinary unavailable for PHP ${PHP_VERSION}"
|
||||
RUN pecl install imagick && docker-php-ext-enable imagick || echo "NOTICE: imagick unavailable for PHP ${PHP_VERSION}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# OPcache configuration (JIT enabled automatically for PHP 8.0+)
|
||||
# ---------------------------------------------------------------------------
|
||||
COPY config/opcache.ini /usr/local/etc/php/conf.d/opcache.ini
|
||||
RUN PHP_MAJOR=$(php -r "echo PHP_MAJOR_VERSION;") && \
|
||||
if [ "$PHP_MAJOR" -ge 8 ]; then \
|
||||
{ echo ""; echo "; JIT (PHP 8.0+)"; echo "opcache.jit=1255"; echo "opcache.jit_buffer_size=128M"; } \
|
||||
>> /usr/local/etc/php/conf.d/opcache.ini; \
|
||||
echo "JIT enabled for PHP $(php -r 'echo PHP_VERSION;')"; \
|
||||
else \
|
||||
echo "JIT skipped (PHP $(php -r 'echo PHP_VERSION;') < 8.0)"; \
|
||||
fi
|
||||
|
||||
# ImageMagick PDF policy (for spatie/pdf-to-image etc.)
|
||||
RUN IMGK_CONF=$(find /etc/ImageMagick* -name policy.xml 2>/dev/null | head -1) && \
|
||||
if [ -n "$IMGK_CONF" ]; then \
|
||||
sed -i 's/<policy domain="coder" rights="none" pattern="PDF" \/>/<policy domain="coder" rights="read|write" pattern="PDF" \/>/g' "$IMGK_CONF" && \
|
||||
sed -i '/<\/policymap>/i\ <policy domain="coder" rights="read|write" pattern="LABEL" />' "$IMGK_CONF"; \
|
||||
fi
|
||||
|
||||
# Custom PHP configuration
|
||||
COPY config/php.ini /usr/local/etc/php/conf.d/99-custom.ini
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Composer
|
||||
# ---------------------------------------------------------------------------
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Node.js + npm
|
||||
# ---------------------------------------------------------------------------
|
||||
ARG NODE_MAJOR=22
|
||||
RUN mkdir -p /etc/apt/keyrings && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
|
||||
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
|
||||
> /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && apt-get install -y --no-install-recommends nodejs && \
|
||||
npm install -g npm@latest && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Image optimization tools (spatie/image-optimizer) + ffmpeg
|
||||
# ---------------------------------------------------------------------------
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
optipng pngquant gifsicle webp libavif-bin ffmpeg \
|
||||
nano procps net-tools \
|
||||
&& npm install -g svgo \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Users & directories
|
||||
# ---------------------------------------------------------------------------
|
||||
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data
|
||||
|
||||
# PsySH config for artisan tinker
|
||||
RUN mkdir -p /var/www/.config/psysh && chown -R www-data:www-data /var/www/.config
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Nginx configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
COPY config/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY config/default.conf /etc/nginx/sites-available/default
|
||||
RUN rm -f /etc/nginx/sites-enabled/default && \
|
||||
ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default && \
|
||||
rm -f /etc/nginx/conf.d/default.conf
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Supervisor configuration
|
||||
# conf.d/ — core programs (php-fpm, nginx), override via volume mount
|
||||
# laravel.d/ — generated at boot from ENABLE_* env vars
|
||||
# custom.d/ — mount your own .conf files here
|
||||
# ---------------------------------------------------------------------------
|
||||
COPY config/supervisord.conf /etc/supervisor/supervisord.conf
|
||||
COPY config/supervisor/php-fpm.conf /etc/supervisor/conf.d/php-fpm.conf
|
||||
COPY config/supervisor/nginx.conf /etc/supervisor/conf.d/nginx.conf
|
||||
RUN mkdir -p /etc/supervisor/conf.d /etc/supervisor/laravel.d /etc/supervisor/custom.d \
|
||||
/var/log/supervisor /var/log/nginx /var/log/php
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Startup script
|
||||
# ---------------------------------------------------------------------------
|
||||
COPY scripts/start-container /usr/local/bin/start-container
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
# Composer cache
|
||||
RUN mkdir -p /.composer && chmod 0777 /.composer
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Environment variables for optional Laravel services
|
||||
# Set to "true" to enable at container start
|
||||
# ---------------------------------------------------------------------------
|
||||
ENV ENABLE_QUEUE=false
|
||||
ENV ENABLE_SCHEDULER=false
|
||||
ENV ENABLE_HORIZON=false
|
||||
ENV ENABLE_LARAVEL_PERMS=0
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["start-container"]
|
||||
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
# docker-laravel
|
||||
|
||||
Multi-version PHP + Nginx Docker image optimized for Laravel (9 – 13).
|
||||
|
||||
The image provides **PHP-FPM, Nginx, Composer, Node.js, Bun**, and common PHP extensions out of the box.
|
||||
It does **not** contain any Laravel code — mount your project at `/var/www/html`.
|
||||
|
||||
## Supported PHP Versions
|
||||
|
||||
| Tag | PHP | Laravel |
|
||||
|-----|-----|---------|
|
||||
| `php7.4` | 7.4 | Legacy (< 9) |
|
||||
| `php8.0` | 8.0 | 9 |
|
||||
| `php8.1` | 8.1 | 9, 10 |
|
||||
| `php8.2` | 8.2 | 9, 10, 11, 12 |
|
||||
| `php8.3` | 8.3 | 10, 11, 12, 13 |
|
||||
| `php8.4` | 8.4 | 11, 12, 13 |
|
||||
| `php8.5` | 8.5 | 12, 13 |
|
||||
| `latest` | 8.4 | (alias) |
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
# 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](docs/examples.md) for full usage examples.
|
||||
|
||||
## Usage in docker-compose.yml
|
||||
|
||||
```yaml
|
||||
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` | `0` | Fix `storage/` and `bootstrap/cache/` permissions on boot |
|
||||
|
||||
## 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:**
|
||||
|
||||
```yaml
|
||||
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`:
|
||||
|
||||
```ini
|
||||
; my-nginx-override.conf
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
autostart=false
|
||||
```
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
server {
|
||||
listen 80;
|
||||
|
||||
index index.php index.html;
|
||||
root /var/www/html/public;
|
||||
|
||||
# Log to Docker (avoid writing to container FS)
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
client_max_body_size 500M;
|
||||
|
||||
# Add X-Forwarded-Proto header
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
fastcgi_param HTTP_PROXY "";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param PHP_SELF $fastcgi_script_name$fastcgi_path_info;
|
||||
fastcgi_param SERVER_NAME $host;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
# Send logs to Docker
|
||||
error_log /dev/stderr warn;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 4096;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Custom headers
|
||||
more_set_headers "Server: Laravel Proxy";
|
||||
more_set_headers "X-Powered-By: Laravel Proxy";
|
||||
|
||||
# Security headers (safe behind Traefik)
|
||||
more_set_headers "X-Frame-Options: SAMEORIGIN";
|
||||
more_set_headers "X-Content-Type-Options: nosniff";
|
||||
more_set_headers "Referrer-Policy: no-referrer-when-downgrade";
|
||||
more_set_headers "X-XSS-Protection: 1; mode=block";
|
||||
more_set_headers "Permissions-Policy: geolocation=(), microphone=(), camera=()";
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_vary on;
|
||||
gzip_types
|
||||
text/plain text/css text/xml application/json application/javascript
|
||||
application/x-javascript application/xml application/xml+rss
|
||||
font/ttf font/otf image/svg+xml;
|
||||
|
||||
# Real IP from Traefik
|
||||
set_real_ip_from 0.0.0.0/0;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
# Buffers & timeouts for Laravel
|
||||
client_max_body_size 50M;
|
||||
client_body_buffer_size 128k;
|
||||
client_header_timeout 30s;
|
||||
client_body_timeout 30s;
|
||||
send_timeout 30s;
|
||||
|
||||
# FastCGI settings for PHP (Laravel)
|
||||
fastcgi_read_timeout 300;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
|
||||
# Logging (to Docker)
|
||||
access_log /dev/stdout;
|
||||
|
||||
# Cache static assets aggressively (ideal for Laravel mix/vite builds)
|
||||
map $sent_http_content_type $static_expires {
|
||||
default off;
|
||||
~*image/ 30d;
|
||||
~*font/ 30d;
|
||||
~*text/css 30d;
|
||||
~*javascript 30d;
|
||||
}
|
||||
|
||||
proxy_headers_hash_max_size 1024;
|
||||
proxy_headers_hash_bucket_size 128;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
; OPcache settings for Laravel (PHP 7.4+)
|
||||
; JIT settings are appended automatically for PHP 8.0+ during build.
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
|
||||
; Memory — generous for large codebases
|
||||
opcache.memory_consumption=256
|
||||
opcache.interned_strings_buffer=32
|
||||
opcache.max_accelerated_files=20000
|
||||
|
||||
; File validation — safe for development; disable for production
|
||||
; (set validate_timestamps=0 and revalidate_freq=0 in production)
|
||||
opcache.validate_timestamps=1
|
||||
opcache.revalidate_freq=2
|
||||
|
||||
; Optimisation
|
||||
opcache.optimization_level=0x7FFEBFFF
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
[PHP]
|
||||
post_max_size = 2G
|
||||
upload_max_filesize = 2G
|
||||
memory_limit = 500M
|
||||
variables_order = EGPCS
|
||||
fastcgi.logging = Off
|
||||
|
||||
; Error Reporting
|
||||
display_errors = Off
|
||||
log_errors = On
|
||||
error_log = /var/log/php/error.log
|
||||
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
|
||||
|
||||
; OPcache Settings
|
||||
; opcache.enable = 1
|
||||
; opcache.memory_consumption = 128
|
||||
; opcache.interned_strings_buffer = 16
|
||||
; opcache.max_accelerated_files = 10000
|
||||
; opcache.validate_timestamps = 1
|
||||
; opcache.revalidate_freq = 2
|
||||
; opcache.fast_shutdown = 1
|
||||
; opcache.enable_cli = 1
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
startsecs=0
|
||||
startretries=10
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[program:php-fpm]
|
||||
command=/usr/local/sbin/php-fpm --nodaemonize
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/proc/1/fd/1
|
||||
logfile_maxbytes=0
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel=info
|
||||
|
||||
[unix_http_server]
|
||||
file=/var/run/supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///var/run/supervisor.sock
|
||||
|
||||
; ==========================================================================
|
||||
; Include directories (order matters — later files can't override earlier ones,
|
||||
; but you can mount over individual files in conf.d/)
|
||||
;
|
||||
; conf.d/ — Core services (php-fpm, nginx). Override by mounting a
|
||||
; replacement file, e.g.:
|
||||
; -v ./my-php-fpm.conf:/etc/supervisor/conf.d/php-fpm.conf
|
||||
;
|
||||
; laravel.d/ — Auto-generated at boot from ENABLE_* env vars.
|
||||
; To use your own instead, set the env var to "false" and
|
||||
; mount your config into custom.d/ or laravel.d/.
|
||||
;
|
||||
; custom.d/ — Mount any extra .conf files here for your own programs.
|
||||
; -v ./my-programs/:/etc/supervisor/custom.d/
|
||||
; ==========================================================================
|
||||
[include]
|
||||
files = /etc/supervisor/conf.d/*.conf /etc/supervisor/laravel.d/*.conf /etc/supervisor/custom.d/*.conf
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
# ===========================================================================
|
||||
# docker-laravel — Multi-version build matrix
|
||||
#
|
||||
# Usage:
|
||||
# docker buildx bake # build all versions
|
||||
# docker buildx bake php-84 # build PHP 8.4 only
|
||||
# docker buildx bake --set "*.platform=linux/amd64,linux/arm64"
|
||||
#
|
||||
# Override registry:
|
||||
# REGISTRY=ghcr.io/myorg IMAGE_NAME=docker-laravel docker buildx bake
|
||||
# ===========================================================================
|
||||
|
||||
variable "REGISTRY" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "IMAGE_NAME" {
|
||||
default = "docker-laravel"
|
||||
}
|
||||
|
||||
variable "NODE_MAJOR" {
|
||||
default = "22"
|
||||
}
|
||||
|
||||
function "tag" {
|
||||
params = [php_version]
|
||||
result = REGISTRY != "" ? "${REGISTRY}/${IMAGE_NAME}:php${php_version}" : "${IMAGE_NAME}:php${php_version}"
|
||||
}
|
||||
|
||||
function "latest_tag" {
|
||||
params = []
|
||||
result = REGISTRY != "" ? "${REGISTRY}/${IMAGE_NAME}:latest" : "${IMAGE_NAME}:latest"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Individual targets
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
target "php-74" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "7.4"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("7.4")]
|
||||
}
|
||||
|
||||
target "php-80" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "8.0"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("8.0")]
|
||||
}
|
||||
|
||||
target "php-81" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "8.1"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("8.1")]
|
||||
}
|
||||
|
||||
target "php-82" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "8.2"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("8.2")]
|
||||
}
|
||||
|
||||
target "php-83" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "8.3"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("8.3")]
|
||||
}
|
||||
|
||||
target "php-84" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "8.4"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("8.4"), latest_tag()]
|
||||
}
|
||||
|
||||
target "php-85" {
|
||||
context = "."
|
||||
dockerfile = "Dockerfile"
|
||||
args = {
|
||||
PHP_VERSION = "8.5"
|
||||
NODE_MAJOR = "${NODE_MAJOR}"
|
||||
}
|
||||
tags = [tag("8.5")]
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Groups
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
group "default" {
|
||||
targets = ["php-74", "php-80", "php-81", "php-82", "php-83", "php-84", "php-85"]
|
||||
}
|
||||
|
||||
group "active" {
|
||||
targets = ["php-82", "php-83", "php-84", "php-85"]
|
||||
}
|
||||
|
||||
group "legacy" {
|
||||
targets = ["php-74", "php-80", "php-81"]
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
# Examples
|
||||
|
||||
## Quick Start with plug-n-pray
|
||||
|
||||
The fastest way to Dockerize any Laravel project:
|
||||
|
||||
```bash
|
||||
# From your Laravel project root:
|
||||
curl -fsSL https://raw.githubusercontent.com/blax-software/docker-laravel/main/scripts/plug-n-pray.sh | bash
|
||||
|
||||
# Or with options:
|
||||
curl -fsSL https://raw.githubusercontent.com/blax-software/docker-laravel/main/scripts/plug-n-pray.sh | bash -s -- \
|
||||
--php=8.4 \
|
||||
--name=my-app \
|
||||
--host=my-app.localhost
|
||||
```
|
||||
|
||||
Or if you have `blax-software/laravel-workkit` installed:
|
||||
|
||||
```bash
|
||||
php artisan workkit:plug-n-pray
|
||||
```
|
||||
|
||||
This generates:
|
||||
- `docker-compose.yml` — Full stack with app, MySQL, Redis, and Traefik
|
||||
- `.env.docker` — Database/Redis connection values to merge into `.env`
|
||||
- `docker/supervisor/` — Directory for custom supervisor programs
|
||||
|
||||
Then:
|
||||
```bash
|
||||
docker network create web # once per machine
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Minimal API (no frontend tooling)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: blaxsoftware/laravel:php8.4
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
ENABLE_QUEUE: "true"
|
||||
ENABLE_SCHEDULER: "true"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Full Stack with Traefik
|
||||
|
||||
Assumes Traefik is already running on the `web` network.
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
web:
|
||||
external: true
|
||||
internal:
|
||||
|
||||
volumes:
|
||||
mysql-data:
|
||||
redis-data:
|
||||
|
||||
services:
|
||||
app:
|
||||
image: blaxsoftware/laravel:php8.4
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
- ./docker/supervisor:/etc/supervisor/custom.d
|
||||
environment:
|
||||
ENABLE_QUEUE: "true"
|
||||
ENABLE_SCHEDULER: "true"
|
||||
ENABLE_LARAVEL_PERMS: "1"
|
||||
networks:
|
||||
- web
|
||||
- internal
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=web
|
||||
- traefik.http.routers.my-app.rule=Host(`my-app.localhost`)
|
||||
- traefik.http.routers.my-app.entrypoints=web
|
||||
- traefik.http.routers.my-app.service=my-app-http
|
||||
- traefik.http.services.my-app-http.loadbalancer.server.port=80
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: secret
|
||||
MYSQL_DATABASE: my_app
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-psecret"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: With Horizon
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: blaxsoftware/laravel:php8.4
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
environment:
|
||||
ENABLE_HORIZON: "true" # replaces basic queue worker
|
||||
ENABLE_SCHEDULER: "true"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Custom Supervisor Programs
|
||||
|
||||
Mount your own `.conf` files into `/etc/supervisor/custom.d/`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: blaxsoftware/laravel:php8.4
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
- ./docker/supervisor/reverb.conf:/etc/supervisor/custom.d/reverb.conf
|
||||
```
|
||||
|
||||
`docker/supervisor/reverb.conf`:
|
||||
```ini
|
||||
[program:reverb]
|
||||
command=/usr/local/bin/php -d variables_order=EGPCS /var/www/html/artisan reverb:start --host=0.0.0.0 --port=8080
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
priority=25
|
||||
startsecs=5
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Override PHP-FPM
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./docker/php-fpm.conf:/etc/supervisor/conf.d/php-fpm.conf
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Multiple PHP Versions in One Compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app-legacy:
|
||||
image: blaxsoftware/laravel:php8.1
|
||||
volumes:
|
||||
- ../legacy-app:/var/www/html
|
||||
|
||||
app-new:
|
||||
image: blaxsoftware/laravel:php8.4
|
||||
volumes:
|
||||
- ../new-app:/var/www/html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## plug-n-pray.sh Options
|
||||
|
||||
| Flag | Default | Description |
|
||||
|------|---------|-------------|
|
||||
| `--php=VERSION` | `8.4` | PHP version |
|
||||
| `--name=NAME` | directory name | Project name (used for container names & Traefik router) |
|
||||
| `--host=HOST` | `NAME.localhost` | Traefik hostname |
|
||||
| `--db=NAME` | project name | MySQL database name |
|
||||
| `--db-pass=PASS` | `secret` | MySQL root password |
|
||||
| `--image=IMAGE` | `blaxsoftware/laravel` | Docker image |
|
||||
| `--no-queue` | — | Disable queue worker |
|
||||
| `--no-scheduler` | — | Disable scheduler |
|
||||
| `--horizon` | — | Enable Horizon (auto-disables basic queue) |
|
||||
| `--no-redis` | — | Skip Redis service |
|
||||
| `--no-mysql` | — | Skip MySQL service |
|
||||
| `--force` | — | Overwrite existing files |
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#!/usr/bin/env bash
|
||||
# ===========================================================================
|
||||
# build.sh — Build all PHP version images with full Laravel tag matrix
|
||||
#
|
||||
# Usage:
|
||||
# ./build.sh # build all versions
|
||||
# ./build.sh 8.4 # build only PHP 8.4
|
||||
# ./build.sh 8.3 8.4 # build PHP 8.3 + 8.4
|
||||
#
|
||||
# Environment:
|
||||
# IMAGE_NAME — image name (default: docker-laravel)
|
||||
# NODE_MAJOR — Node.js major ver (default: 22)
|
||||
# PLATFORM — e.g. linux/amd64 (default: current platform)
|
||||
# ===========================================================================
|
||||
set -euo pipefail
|
||||
|
||||
IMAGE_NAME="${IMAGE_NAME:-docker-laravel}"
|
||||
NODE_MAJOR="${NODE_MAJOR:-22}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PHP → Laravel version mapping
|
||||
# ---------------------------------------------------------------------------
|
||||
declare -A PHP_LARAVEL_MAP=(
|
||||
["7.4"]=""
|
||||
["8.0"]="9"
|
||||
["8.1"]="9 10"
|
||||
["8.2"]="9 10 11 12"
|
||||
["8.3"]="10 11 12 13"
|
||||
["8.4"]="11 12 13"
|
||||
["8.5"]="12 13"
|
||||
)
|
||||
|
||||
# Recommended (highest) PHP version per Laravel version → gets the bare `laravelN` tag
|
||||
declare -A LARAVEL_RECOMMENDED_PHP=(
|
||||
["9"]="8.1"
|
||||
["10"]="8.3"
|
||||
["11"]="8.4"
|
||||
["12"]="8.5"
|
||||
["13"]="8.5"
|
||||
)
|
||||
|
||||
# Which PHP version gets the `latest` tag
|
||||
LATEST_PHP="8.4"
|
||||
|
||||
ALL_PHP_VERSIONS=("7.4" "8.0" "8.1" "8.2" "8.3" "8.4" "8.5")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Determine which versions to build
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ $# -gt 0 ]; then
|
||||
BUILD_VERSIONS=("$@")
|
||||
else
|
||||
BUILD_VERSIONS=("${ALL_PHP_VERSIONS[@]}")
|
||||
fi
|
||||
|
||||
# Validate requested versions
|
||||
for v in "${BUILD_VERSIONS[@]}"; do
|
||||
if [[ ! -v "PHP_LARAVEL_MAP[$v]" ]]; then
|
||||
echo "ERROR: Unknown PHP version: $v"
|
||||
echo "Available: ${ALL_PHP_VERSIONS[*]}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build
|
||||
# ---------------------------------------------------------------------------
|
||||
TOTAL=${#BUILD_VERSIONS[@]}
|
||||
CURRENT=0
|
||||
FAILED=()
|
||||
|
||||
PLATFORM_ARG=""
|
||||
if [ -n "${PLATFORM:-}" ]; then
|
||||
PLATFORM_ARG="--platform=${PLATFORM}"
|
||||
fi
|
||||
|
||||
for PHP_VERSION in "${BUILD_VERSIONS[@]}"; do
|
||||
CURRENT=$((CURRENT + 1))
|
||||
|
||||
# Collect all tags for this PHP version
|
||||
TAGS=()
|
||||
TAGS+=("${IMAGE_NAME}:php${PHP_VERSION}")
|
||||
|
||||
# Laravel combo tags: laravel12-php8.4, etc.
|
||||
LARAVEL_VERSIONS="${PHP_LARAVEL_MAP[$PHP_VERSION]}"
|
||||
for LV in $LARAVEL_VERSIONS; do
|
||||
TAGS+=("${IMAGE_NAME}:laravel${LV}-php${PHP_VERSION}")
|
||||
|
||||
# Convenience bare tag: laravelN → recommended PHP
|
||||
if [ "${LARAVEL_RECOMMENDED_PHP[$LV]}" = "$PHP_VERSION" ]; then
|
||||
TAGS+=("${IMAGE_NAME}:laravel${LV}")
|
||||
fi
|
||||
done
|
||||
|
||||
# latest tag
|
||||
if [ "$PHP_VERSION" = "$LATEST_PHP" ]; then
|
||||
TAGS+=("${IMAGE_NAME}:latest")
|
||||
fi
|
||||
|
||||
TAG_ARGS=""
|
||||
TAG_LIST=""
|
||||
for T in "${TAGS[@]}"; do
|
||||
TAG_ARGS="${TAG_ARGS} -t ${T}"
|
||||
TAG_LIST="${TAG_LIST} ${T}\n"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "==========================================="
|
||||
echo " [${CURRENT}/${TOTAL}] Building PHP ${PHP_VERSION}"
|
||||
echo "==========================================="
|
||||
echo -e "Tags:\n${TAG_LIST}"
|
||||
|
||||
if docker build ${PLATFORM_ARG} \
|
||||
--build-arg PHP_VERSION="${PHP_VERSION}" \
|
||||
--build-arg NODE_MAJOR="${NODE_MAJOR}" \
|
||||
${TAG_ARGS} \
|
||||
. ; then
|
||||
echo "[${CURRENT}/${TOTAL}] PHP ${PHP_VERSION} — OK"
|
||||
else
|
||||
echo "[${CURRENT}/${TOTAL}] PHP ${PHP_VERSION} — FAILED"
|
||||
FAILED+=("$PHP_VERSION")
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Summary
|
||||
# ---------------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "==========================================="
|
||||
echo " Build complete"
|
||||
echo "==========================================="
|
||||
echo "Succeeded: $((TOTAL - ${#FAILED[@]}))/${TOTAL}"
|
||||
|
||||
if [ ${#FAILED[@]} -gt 0 ]; then
|
||||
echo "Failed: ${FAILED[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
#!/usr/bin/env bash
|
||||
# ===========================================================================
|
||||
# plug-n-pray.sh — Generate a boilerplate Docker setup for any Laravel project
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL https://raw.githubusercontent.com/blax-software/docker-laravel/main/scripts/plug-n-pray.sh | bash
|
||||
# # or locally:
|
||||
# ./plug-n-pray.sh
|
||||
# ./plug-n-pray.sh --php=8.4 --name=my-app --host=my-app.localhost
|
||||
#
|
||||
# Assumes Traefik is already running on the "web" network.
|
||||
#
|
||||
# What it creates:
|
||||
# docker-compose.yml — App + MySQL + Redis (with Traefik labels)
|
||||
# .env.docker — Docker-specific env vars
|
||||
# docker/supervisor/ — Empty custom supervisor dir
|
||||
# ===========================================================================
|
||||
set -euo pipefail
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Defaults
|
||||
# ---------------------------------------------------------------------------
|
||||
PHP_VERSION="8.4"
|
||||
PROJECT_NAME=""
|
||||
TRAEFIK_HOST=""
|
||||
DB_NAME=""
|
||||
DB_PASSWORD="secret"
|
||||
IMAGE="blaxsoftware/laravel"
|
||||
ENABLE_QUEUE="true"
|
||||
ENABLE_SCHEDULER="true"
|
||||
ENABLE_HORIZON="false"
|
||||
ENABLE_REDIS="true"
|
||||
ENABLE_MYSQL="true"
|
||||
ENABLE_WEBSOCKET="false"
|
||||
WEBSOCKET_PORT="6001"
|
||||
FORCE="false"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Parse args
|
||||
# ---------------------------------------------------------------------------
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--php=*) PHP_VERSION="${arg#*=}" ;;
|
||||
--name=*) PROJECT_NAME="${arg#*=}" ;;
|
||||
--host=*) TRAEFIK_HOST="${arg#*=}" ;;
|
||||
--db=*) DB_NAME="${arg#*=}" ;;
|
||||
--db-pass=*) DB_PASSWORD="${arg#*=}" ;;
|
||||
--image=*) IMAGE="${arg#*=}" ;;
|
||||
--no-queue) ENABLE_QUEUE="false" ;;
|
||||
--no-scheduler) ENABLE_SCHEDULER="false" ;;
|
||||
--horizon) ENABLE_HORIZON="true" ;;
|
||||
--no-redis) ENABLE_REDIS="false" ;;
|
||||
--no-mysql) ENABLE_MYSQL="false" ;;
|
||||
--websocket) ENABLE_WEBSOCKET="true" ;;
|
||||
--websocket-port=*) WEBSOCKET_PORT="${arg#*=}" ;;
|
||||
--force) FORCE="true" ;;
|
||||
--help|-h)
|
||||
echo "Usage: plug-n-pray.sh [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --php=VERSION PHP version (default: 8.4)"
|
||||
echo " --name=NAME Project/compose name (default: directory name)"
|
||||
echo " --host=HOST Traefik hostname (default: NAME.localhost)"
|
||||
echo " --db=NAME Database name (default: PROJECT_NAME)"
|
||||
echo " --db-pass=PASS Database password (default: secret)"
|
||||
echo " --image=IMAGE Docker image (default: blaxsoftware/laravel)"
|
||||
echo " --no-queue Disable queue worker"
|
||||
echo " --no-scheduler Disable scheduler"
|
||||
echo " --horizon Enable Horizon (disables basic queue)"
|
||||
echo " --no-redis Skip Redis service"
|
||||
echo " --no-mysql Skip MySQL service"
|
||||
echo " --websocket Enable WebSocket server (blax/laravel-websockets)"
|
||||
echo " --websocket-port=N WebSocket port (default: 6001)"
|
||||
echo " --force Overwrite existing files"
|
||||
echo " --help Show this help"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $arg (try --help)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Derive defaults from current directory
|
||||
if [ -z "$PROJECT_NAME" ]; then
|
||||
PROJECT_NAME="$(basename "$(pwd)")"
|
||||
# Sanitize: lowercase, replace non-alnum with dash
|
||||
PROJECT_NAME="$(echo "$PROJECT_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')"
|
||||
fi
|
||||
|
||||
if [ -z "$TRAEFIK_HOST" ]; then
|
||||
TRAEFIK_HOST="${PROJECT_NAME}.localhost"
|
||||
fi
|
||||
|
||||
if [ -z "$DB_NAME" ]; then
|
||||
DB_NAME="$(echo "$PROJECT_NAME" | sed 's/-/_/g')"
|
||||
fi
|
||||
|
||||
# If horizon is on, disable basic queue
|
||||
if [ "$ENABLE_HORIZON" = "true" ]; then
|
||||
ENABLE_QUEUE="false"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Safety check
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ "$FORCE" != "true" ] && [ -f "docker-compose.yml" ]; then
|
||||
echo "docker-compose.yml already exists. Use --force to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
echo " plug-n-pray 🙏"
|
||||
echo "=========================================="
|
||||
echo " Project: $PROJECT_NAME"
|
||||
echo " PHP: $PHP_VERSION"
|
||||
echo " Image: ${IMAGE}:php${PHP_VERSION}"
|
||||
echo " Traefik: $TRAEFIK_HOST"
|
||||
echo " Database: ${ENABLE_MYSQL:+MySQL ($DB_NAME)}${ENABLE_MYSQL:+}$([ "$ENABLE_MYSQL" = "false" ] && echo "disabled")"
|
||||
echo " Redis: $ENABLE_REDIS"
|
||||
echo " Queue: $ENABLE_QUEUE"
|
||||
echo " Scheduler: $ENABLE_SCHEDULER"
|
||||
echo " Horizon: $ENABLE_HORIZON"
|
||||
echo " WebSocket: ${ENABLE_WEBSOCKET}$([ "$ENABLE_WEBSOCKET" = "true" ] && echo " (port ${WEBSOCKET_PORT})")"
|
||||
echo "=========================================="
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Create directory for custom supervisor configs
|
||||
# ---------------------------------------------------------------------------
|
||||
mkdir -p docker/supervisor
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Generate docker-compose.yml
|
||||
# ---------------------------------------------------------------------------
|
||||
cat > docker-compose.yml <<YAML
|
||||
# ===========================================================================
|
||||
# Generated by plug-n-pray.sh — $(date +%Y-%m-%d)
|
||||
# Image: ${IMAGE}:php${PHP_VERSION}
|
||||
# ===========================================================================
|
||||
|
||||
networks:
|
||||
web:
|
||||
external: true
|
||||
internal:
|
||||
driver: bridge
|
||||
|
||||
YAML
|
||||
|
||||
# --- Volumes ---
|
||||
VOLUMES_SECTION=""
|
||||
if [ "$ENABLE_MYSQL" = "true" ]; then
|
||||
VOLUMES_SECTION="volumes:
|
||||
mysql-data:
|
||||
"
|
||||
fi
|
||||
if [ "$ENABLE_REDIS" = "true" ]; then
|
||||
if [ -n "$VOLUMES_SECTION" ]; then
|
||||
VOLUMES_SECTION="${VOLUMES_SECTION} redis-data:
|
||||
"
|
||||
else
|
||||
VOLUMES_SECTION="volumes:
|
||||
redis-data:
|
||||
"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$VOLUMES_SECTION" ]; then
|
||||
echo "$VOLUMES_SECTION" >> docker-compose.yml
|
||||
fi
|
||||
|
||||
# --- Services ---
|
||||
cat >> docker-compose.yml <<YAML
|
||||
services:
|
||||
# -------------------------------------------------------------------------
|
||||
# App (PHP-FPM + Nginx)
|
||||
# -------------------------------------------------------------------------
|
||||
app:
|
||||
image: ${IMAGE}:php${PHP_VERSION}
|
||||
container_name: ${PROJECT_NAME}-app
|
||||
restart: unless-stopped
|
||||
working_dir: /var/www/html
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
- ./docker/supervisor:/etc/supervisor/custom.d
|
||||
environment:
|
||||
ENABLE_QUEUE: "${ENABLE_QUEUE}"
|
||||
ENABLE_SCHEDULER: "${ENABLE_SCHEDULER}"
|
||||
ENABLE_HORIZON: "${ENABLE_HORIZON}"
|
||||
ENABLE_LARAVEL_PERMS: "1"
|
||||
$([ "$ENABLE_WEBSOCKET" = "true" ] && echo " PUSHER_PORT: \"${WEBSOCKET_PORT}\"")
|
||||
networks:
|
||||
- web
|
||||
- internal
|
||||
depends_on:
|
||||
YAML
|
||||
|
||||
if [ "$ENABLE_MYSQL" = "true" ]; then
|
||||
cat >> docker-compose.yml <<YAML
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
YAML
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_REDIS" = "true" ]; then
|
||||
cat >> docker-compose.yml <<YAML
|
||||
redis:
|
||||
condition: service_healthy
|
||||
YAML
|
||||
fi
|
||||
|
||||
cat >> docker-compose.yml <<YAML
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=web
|
||||
# HTTP
|
||||
- traefik.http.routers.${PROJECT_NAME}.rule=Host(\`${TRAEFIK_HOST}\`)
|
||||
- traefik.http.routers.${PROJECT_NAME}.entrypoints=web
|
||||
- traefik.http.routers.${PROJECT_NAME}.service=${PROJECT_NAME}-http
|
||||
- traefik.http.services.${PROJECT_NAME}-http.loadbalancer.server.port=80
|
||||
# HTTPS
|
||||
- traefik.http.routers.${PROJECT_NAME}-tls.rule=Host(\`${TRAEFIK_HOST}\`)
|
||||
- traefik.http.routers.${PROJECT_NAME}-tls.entrypoints=websecure
|
||||
- traefik.http.routers.${PROJECT_NAME}-tls.tls=true
|
||||
- traefik.http.routers.${PROJECT_NAME}-tls.service=${PROJECT_NAME}-https
|
||||
- traefik.http.services.${PROJECT_NAME}-https.loadbalancer.server.port=80
|
||||
$(if [ "$ENABLE_WEBSOCKET" = "true" ]; then
|
||||
cat <<WSLABELS
|
||||
# WebSocket
|
||||
- traefik.http.routers.${PROJECT_NAME}-ws.rule=Host(\`ws-${TRAEFIK_HOST}\`)
|
||||
- traefik.http.routers.${PROJECT_NAME}-ws.entrypoints=web
|
||||
- traefik.http.routers.${PROJECT_NAME}-ws.service=${PROJECT_NAME}-ws
|
||||
- traefik.http.services.${PROJECT_NAME}-ws.loadbalancer.server.port=${WEBSOCKET_PORT}
|
||||
- traefik.http.routers.${PROJECT_NAME}-wss.rule=Host(\`ws-${TRAEFIK_HOST}\`)
|
||||
- traefik.http.routers.${PROJECT_NAME}-wss.entrypoints=websecure
|
||||
- traefik.http.routers.${PROJECT_NAME}-wss.tls=true
|
||||
- traefik.http.routers.${PROJECT_NAME}-wss.service=${PROJECT_NAME}-wss
|
||||
- traefik.http.services.${PROJECT_NAME}-wss.loadbalancer.server.port=${WEBSOCKET_PORT}
|
||||
WSLABELS
|
||||
fi)
|
||||
YAML
|
||||
|
||||
# --- MySQL ---
|
||||
if [ "$ENABLE_MYSQL" = "true" ]; then
|
||||
cat >> docker-compose.yml <<YAML
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MySQL
|
||||
# -------------------------------------------------------------------------
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: ${PROJECT_NAME}-mysql
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
|
||||
MYSQL_DATABASE: "${DB_NAME}"
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${DB_PASSWORD}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
YAML
|
||||
fi
|
||||
|
||||
# --- Redis ---
|
||||
if [ "$ENABLE_REDIS" = "true" ]; then
|
||||
cat >> docker-compose.yml <<YAML
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Redis
|
||||
# -------------------------------------------------------------------------
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ${PROJECT_NAME}-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
YAML
|
||||
fi
|
||||
|
||||
# --- WebSocket supervisor config ---
|
||||
if [ "$ENABLE_WEBSOCKET" = "true" ]; then
|
||||
cat > docker/supervisor/websocket.conf <<CONF
|
||||
[program:websocket]
|
||||
command=/usr/local/bin/php -d variables_order=EGPCS /var/www/html/artisan websockets:serve --host=0.0.0.0 --port=${WEBSOCKET_PORT}
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
priority=30
|
||||
startsecs=5
|
||||
startretries=100
|
||||
stopsignal=TERM
|
||||
stopwaitsecs=15
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
CONF
|
||||
echo " Created docker/supervisor/websocket.conf"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Generate .env.docker
|
||||
# ---------------------------------------------------------------------------
|
||||
cat > .env.docker <<ENV
|
||||
# ===========================================================================
|
||||
# Docker environment — generated by plug-n-pray.sh
|
||||
# Merge these into your .env or source this file
|
||||
# ===========================================================================
|
||||
|
||||
# App
|
||||
APP_URL=http://${TRAEFIK_HOST}
|
||||
ENV
|
||||
|
||||
if [ "$ENABLE_MYSQL" = "true" ]; then
|
||||
cat >> .env.docker <<ENV
|
||||
|
||||
# Database
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=mysql
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=${DB_NAME}
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=${DB_PASSWORD}
|
||||
ENV
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_REDIS" = "true" ]; then
|
||||
cat >> .env.docker <<ENV
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
CACHE_STORE=redis
|
||||
SESSION_DRIVER=redis
|
||||
QUEUE_CONNECTION=redis
|
||||
ENV
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_WEBSOCKET" = "true" ]; then
|
||||
cat >> .env.docker <<ENV
|
||||
|
||||
# WebSocket (blax/laravel-websockets)
|
||||
BROADCAST_CONNECTION=pusher
|
||||
PUSHER_APP_ID=app-id
|
||||
PUSHER_APP_KEY=app-key
|
||||
PUSHER_APP_SECRET=app-secret
|
||||
PUSHER_HOST=127.0.0.1
|
||||
PUSHER_PORT=${WEBSOCKET_PORT}
|
||||
PUSHER_SCHEME=http
|
||||
LARAVEL_WEBSOCKETS_PORT=${WEBSOCKET_PORT}
|
||||
ENV
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Done
|
||||
# ---------------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " Files created:"
|
||||
echo "=========================================="
|
||||
echo " docker-compose.yml — Full stack (app + db + redis, Traefik labels)"
|
||||
echo " .env.docker — Environment variables to merge into .env"
|
||||
echo " docker/supervisor/ — Mount dir for custom supervisor programs"
|
||||
echo ""
|
||||
echo " Next steps:"
|
||||
echo " 1. Merge .env.docker into your .env"
|
||||
echo " 2. Create the external network (once): docker network create web"
|
||||
echo " 3. Start: docker compose up -d"
|
||||
echo " 4. Visit: http://${TRAEFIK_HOST}"
|
||||
echo ""
|
||||
echo " Pray it works. 🙏"
|
||||
echo "=========================================="
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#!/usr/bin/env bash
|
||||
# ===========================================================================
|
||||
# publish.sh — Push all built images to a container registry
|
||||
#
|
||||
# Usage:
|
||||
# REGISTRY=ghcr.io/myorg ./publish.sh # push all versions
|
||||
# REGISTRY=ghcr.io/myorg ./publish.sh 8.4 # push only PHP 8.4 tags
|
||||
# REGISTRY=ghcr.io/myorg ./publish.sh 8.3 8.4 # push PHP 8.3 + 8.4
|
||||
#
|
||||
# Environment:
|
||||
# REGISTRY — registry prefix (REQUIRED, e.g. ghcr.io/myorg)
|
||||
# IMAGE_NAME — image name (default: docker-laravel)
|
||||
# DRY_RUN — set to 1 to print commands without executing
|
||||
# ===========================================================================
|
||||
set -euo pipefail
|
||||
|
||||
if [ -z "${REGISTRY:-}" ]; then
|
||||
echo "ERROR: REGISTRY is required."
|
||||
echo ""
|
||||
echo "Usage: REGISTRY=ghcr.io/myorg ./publish.sh [php_versions...]"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " REGISTRY=ghcr.io/myorg ./publish.sh"
|
||||
echo " REGISTRY=docker.io/myuser ./publish.sh 8.4"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IMAGE_NAME="${IMAGE_NAME:-docker-laravel}"
|
||||
LOCAL="${IMAGE_NAME}"
|
||||
REMOTE="${REGISTRY}/${IMAGE_NAME}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PHP → Laravel version mapping (must match build.sh)
|
||||
# ---------------------------------------------------------------------------
|
||||
declare -A PHP_LARAVEL_MAP=(
|
||||
["7.4"]=""
|
||||
["8.0"]="9"
|
||||
["8.1"]="9 10"
|
||||
["8.2"]="9 10 11 12"
|
||||
["8.3"]="10 11 12 13"
|
||||
["8.4"]="11 12 13"
|
||||
["8.5"]="12 13"
|
||||
)
|
||||
|
||||
declare -A LARAVEL_RECOMMENDED_PHP=(
|
||||
["9"]="8.1"
|
||||
["10"]="8.3"
|
||||
["11"]="8.4"
|
||||
["12"]="8.5"
|
||||
["13"]="8.5"
|
||||
)
|
||||
|
||||
LATEST_PHP="8.4"
|
||||
ALL_PHP_VERSIONS=("7.4" "8.0" "8.1" "8.2" "8.3" "8.4" "8.5")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Determine which versions to push
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ $# -gt 0 ]; then
|
||||
PUSH_VERSIONS=("$@")
|
||||
else
|
||||
PUSH_VERSIONS=("${ALL_PHP_VERSIONS[@]}")
|
||||
fi
|
||||
|
||||
for v in "${PUSH_VERSIONS[@]}"; do
|
||||
if [[ ! -v "PHP_LARAVEL_MAP[$v]" ]]; then
|
||||
echo "ERROR: Unknown PHP version: $v"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helper
|
||||
# ---------------------------------------------------------------------------
|
||||
run() {
|
||||
if [ "${DRY_RUN:-0}" = "1" ]; then
|
||||
echo "[dry-run] $*"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
tag_and_push() {
|
||||
local LOCAL_TAG="$1"
|
||||
local REMOTE_TAG="$2"
|
||||
run docker tag "${LOCAL_TAG}" "${REMOTE_TAG}"
|
||||
run docker push "${REMOTE_TAG}"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Push
|
||||
# ---------------------------------------------------------------------------
|
||||
TOTAL=0
|
||||
PUSHED=0
|
||||
|
||||
for PHP_VERSION in "${PUSH_VERSIONS[@]}"; do
|
||||
echo ""
|
||||
echo "==========================================="
|
||||
echo " Pushing PHP ${PHP_VERSION}"
|
||||
echo "==========================================="
|
||||
|
||||
# Base PHP tag
|
||||
tag_and_push "${LOCAL}:php${PHP_VERSION}" "${REMOTE}:php${PHP_VERSION}"
|
||||
TOTAL=$((TOTAL + 1)); PUSHED=$((PUSHED + 1))
|
||||
|
||||
# Laravel combo tags
|
||||
LARAVEL_VERSIONS="${PHP_LARAVEL_MAP[$PHP_VERSION]}"
|
||||
for LV in $LARAVEL_VERSIONS; do
|
||||
tag_and_push "${LOCAL}:php${PHP_VERSION}" "${REMOTE}:laravel${LV}-php${PHP_VERSION}"
|
||||
TOTAL=$((TOTAL + 1)); PUSHED=$((PUSHED + 1))
|
||||
|
||||
# Bare laravelN tag
|
||||
if [ "${LARAVEL_RECOMMENDED_PHP[$LV]}" = "$PHP_VERSION" ]; then
|
||||
tag_and_push "${LOCAL}:php${PHP_VERSION}" "${REMOTE}:laravel${LV}"
|
||||
TOTAL=$((TOTAL + 1)); PUSHED=$((PUSHED + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# latest
|
||||
if [ "$PHP_VERSION" = "$LATEST_PHP" ]; then
|
||||
tag_and_push "${LOCAL}:php${PHP_VERSION}" "${REMOTE}:latest"
|
||||
TOTAL=$((TOTAL + 1)); PUSHED=$((PUSHED + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Summary
|
||||
# ---------------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "==========================================="
|
||||
echo " Publish complete"
|
||||
echo "==========================================="
|
||||
echo "Pushed ${PUSHED} tags to ${REGISTRY}/${IMAGE_NAME}"
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "=========================================="
|
||||
echo " docker-laravel container starting"
|
||||
echo "=========================================="
|
||||
echo "Date: $(date)"
|
||||
echo "Hostname: $(hostname)"
|
||||
echo "PHP: $(php -r 'echo PHP_VERSION;')"
|
||||
echo "Node: $(node --version 2>/dev/null || echo 'n/a')"
|
||||
echo "Composer: $(composer --version --no-ansi 2>/dev/null | head -1 || echo 'n/a')"
|
||||
echo "=========================================="
|
||||
|
||||
start_ts=$(date +%s)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1) Writable directories
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "[1/5] Preparing writable dirs..."
|
||||
|
||||
mkdir -p /.composer && chmod 0777 /.composer 2>/dev/null || true
|
||||
|
||||
if [ "${ENABLE_LARAVEL_PERMS:-0}" = "1" ]; then
|
||||
echo " ENABLE_LARAVEL_PERMS=1 — applying targeted writable-dir fixes"
|
||||
for p in /var/www/html/storage /var/www/html/bootstrap/cache; do
|
||||
if [ -d "$p" ]; then
|
||||
chmod ug+rwX "$p" 2>/dev/null || true
|
||||
else
|
||||
echo " WARN: $p does not exist"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo " Skipping Laravel chmod (set ENABLE_LARAVEL_PERMS=1 to enable)"
|
||||
fi
|
||||
|
||||
mkdir -p /var/log/supervisor /var/log/nginx /var/log/php
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2) Generate optional supervisor programs based on ENABLE_* env vars
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "[2/5] Configuring services..."
|
||||
|
||||
echo " Core programs (conf.d/):"
|
||||
for f in /etc/supervisor/conf.d/*.conf; do
|
||||
[ -f "$f" ] && echo " $(basename "$f")"
|
||||
done
|
||||
|
||||
LARAVEL_D="/etc/supervisor/laravel.d"
|
||||
rm -f "${LARAVEL_D}"/*.conf 2>/dev/null || true
|
||||
|
||||
if [ "${ENABLE_QUEUE:-false}" = "true" ]; then
|
||||
echo " + queue worker enabled"
|
||||
cat > "${LARAVEL_D}/queue.conf" <<'CONF'
|
||||
[program:queue]
|
||||
command=/usr/local/bin/php -d variables_order=EGPCS /var/www/html/artisan queue:work --tries=3 --sleep=5 --timeout=600 --max-jobs=500 --max-time=3600
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
priority=20
|
||||
startsecs=5
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
CONF
|
||||
fi
|
||||
|
||||
if [ "${ENABLE_SCHEDULER:-false}" = "true" ]; then
|
||||
echo " + scheduler enabled"
|
||||
cat > "${LARAVEL_D}/scheduler.conf" <<'CONF'
|
||||
[program:scheduler]
|
||||
command=/usr/local/bin/php -d variables_order=EGPCS /var/www/html/artisan schedule:work
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
priority=20
|
||||
startsecs=5
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
CONF
|
||||
fi
|
||||
|
||||
if [ "${ENABLE_HORIZON:-false}" = "true" ]; then
|
||||
echo " + Horizon enabled"
|
||||
cat > "${LARAVEL_D}/horizon.conf" <<'CONF'
|
||||
[program:horizon]
|
||||
command=/usr/local/bin/php -d variables_order=EGPCS /var/www/html/artisan horizon
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
priority=20
|
||||
startsecs=5
|
||||
stdout_logfile=/proc/1/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/proc/1/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
CONF
|
||||
fi
|
||||
|
||||
# Report custom programs
|
||||
CUSTOM_COUNT=$(find /etc/supervisor/custom.d/ -name '*.conf' 2>/dev/null | wc -l)
|
||||
if [ "$CUSTOM_COUNT" -gt 0 ]; then
|
||||
echo " Custom programs (custom.d/):"
|
||||
for f in /etc/supervisor/custom.d/*.conf; do
|
||||
[ -f "$f" ] && echo " $(basename "$f")"
|
||||
done
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3) Config tests
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "[3/5] Testing configs..."
|
||||
|
||||
php-fpm -t 2>&1 || echo " PHP-FPM config test failed (continuing)"
|
||||
nginx -t 2>&1 || echo " Nginx config test failed (continuing)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4) Diagnostics
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "[4/5] Environment"
|
||||
echo " APP_ENV=${APP_ENV:-<unset>}"
|
||||
echo " APP_DEBUG=${APP_DEBUG:-<unset>}"
|
||||
echo " ENABLE_QUEUE=${ENABLE_QUEUE:-false}"
|
||||
echo " ENABLE_SCHEDULER=${ENABLE_SCHEDULER:-false}"
|
||||
echo " ENABLE_HORIZON=${ENABLE_HORIZON:-false}"
|
||||
|
||||
end_ts=$(date +%s)
|
||||
echo " Preflight took $((end_ts - start_ts))s"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5) Launch
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "[5/5] Running ad-hoc command: $*"
|
||||
php-fpm -D
|
||||
sleep 1
|
||||
nginx
|
||||
exec gosu 1000 "$@"
|
||||
else
|
||||
echo "[5/5] Starting Supervisord..."
|
||||
echo "=========================================="
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||
fi
|
||||
Loading…
Reference in New Issue