From 817c38d71219b8f8c65781b7d9790b6acfa516c8 Mon Sep 17 00:00:00 2001 From: Jordy Schreuders <3071062+99linesofcode@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:29:00 +0200 Subject: [PATCH 1/5] fix: container build issues caused by PECL being deprecated PIE will be the way forward but I'm not entirely clear on what that will look like in an Alpine context. Eventually, PIE will be able to automatically install PHP extensions from a composer file so this will need some more work once the way that is intended to be used materializes. --- docker-compose.yaml | 5 ++-- frankenphp/Caddyfile | 2 +- frankenphp/Dockerfile | 60 +++++++++++++++++++++++++++---------------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index cfdba83..cf48612 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -7,7 +7,7 @@ services: mailpit: container_name: ${APP_NAME}-mailpit healthcheck: - test: ["CMD", "curl", "-Ss", "http://localhost:8025/livez"] + test: ['CMD', 'curl', '-Ss', 'http://localhost:8025/livez'] retries: 3 timeout: 5s image: axllent/mailpit:latest @@ -36,10 +36,11 @@ services: - XDEBUG_MODE=${PHP_XDEBUG_MODE:-off} - XDEBUG_CONFIG=${PHP_XDEBUG_CONFIG:-client_host=host.docker.internal output_dir=/tmp/xdebug profiler_output_name=cachegrind.out.%R.%u} extra_hosts: - - "host.docker.internal:host-gateway" # for accessing the host from inside the container + - 'host.docker.internal:host-gateway' # for accessing the host from inside the container ports: - ${FORWARD_PHP_HTTP_PORT:-80}:80 - ${FORWARD_PHP_HTTPS_PORT:-443}:443 + - ${FORWARD_PHP_HTTPS_PORT:-443}:443/udp restart: unless-stopped working_dir: /app diff --git a/frankenphp/Caddyfile b/frankenphp/Caddyfile index 9d95689..f017c25 100644 --- a/frankenphp/Caddyfile +++ b/frankenphp/Caddyfile @@ -1,5 +1,5 @@ { - acme_dns cloudflare {$CLOUDFLARE_DNS_API_TOKEN} + acme_dns cloudflare {$CLOUDFLARE_DNS_API_TOKEN} {$CADDY_GLOBAL_OPTIONS} diff --git a/frankenphp/Dockerfile b/frankenphp/Dockerfile index 37b5051..e1059fc 100644 --- a/frankenphp/Dockerfile +++ b/frankenphp/Dockerfile @@ -1,20 +1,40 @@ # syntax=docker/dockerfile:1 -ARG PHP_VERSION="8.4" -ARG BASE_IMAGE="dunglas/frankenphp:php${PHP_VERSION}-alpine" +ARG VERSION="8.5" +ARG BASE_IMAGE="dunglas/frankenphp:php${VERSION}-alpine" FROM ${BASE_IMAGE} AS base LABEL org.opencontainers.image.authors="99linesofcode@gmail.com" -RUN set -eux; \ - install-php-extensions \ - bcmath \ - pdo_mysql \ - pdo_pgsql \ - intl \ - zip \ - redis; +ARG VERSION + +RUN apk add --no-cache \ + php${VERSION/./}-bcmath \ + php${VERSION/./}-ctype \ + php${VERSION/./}-curl \ + php${VERSION/./}-dom \ + php${VERSION/./}-fileinfo \ + php${VERSION/./}-fpm \ + php${VERSION/./}-iconv \ + php${VERSION/./}-intl \ + php${VERSION/./}-json \ + php${VERSION/./}-mbstring \ + php${VERSION/./}-opcache \ + php${VERSION/./}-openssl \ + php${VERSION/./}-pcntl \ + php${VERSION/./}-phar \ + php${VERSION/./}-pdo_mysql \ + php${VERSION/./}-pdo_pgsql \ + php${VERSION/./}-pdo_sqlite \ + php${VERSION/./}-session \ + php${VERSION/./}-simplexml \ + php${VERSION/./}-tokenizer \ + php${VERSION/./}-xml \ + php${VERSION/./}-xmlwriter \ + php${VERSION/./}-zlib \ + php${VERSION/./}-zip \ + php${VERSION/./}-pecl-redis; WORKDIR /app @@ -24,10 +44,9 @@ WORKDIR /app FROM base AS development -RUN set -eux; \ - install-php-extensions \ - @composer \ - xdebug; +RUN apk add --no-cache \ + composer \ + php${VERSION/./}-pecl-xdebug; COPY --link ./frankenphp/php.ini-development ${PHP_INI_DIR}/php.ini @@ -44,8 +63,7 @@ ENV CGO_ENABLED=1 \ XCADDY_SETCAP=1 \ XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" -RUN set -eux; \ - xcaddy build \ +RUN xcaddy build \ --output /usr/local/bin/frankenphp \ --with github.com/dunglas/frankenphp=./ \ --with github.com/dunglas/frankenphp/caddy=./caddy/ \ @@ -53,15 +71,13 @@ RUN set -eux; \ FROM base AS composer-builder -RUN set -eux; \ - install-php-extensions \ - @composer \ - && composer install -n --no-cache --prefer-dist --no-dev --no-scripts -o -a; +RUN apk add --no-cache \ + composer && \ + composer install -n --no-cache --prefer-dist --no-dev --no-scripts -o -a; FROM base AS production -RUN set -eux; \ - mv ${PHP_INI_DIR}/php.ini-production ${PHP_INI_DIR}/php.ini; +RUN mv ${PHP_INI_DIR}/php.ini-production ${PHP_INI_DIR}/php.ini; # Replace the official binary by the one containing our custom modules COPY --from=caddy-builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp From cb52f2ddff0e37147a57551a1524ad0b9b90170d Mon Sep 17 00:00:00 2001 From: Jordy Schreuders <3071062+99linesofcode@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:30:57 +0200 Subject: [PATCH 2/5] chore: yaml formatting --- docker-compose.yaml.dist | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docker-compose.yaml.dist b/docker-compose.yaml.dist index fcff6b9..fbea38c 100644 --- a/docker-compose.yaml.dist +++ b/docker-compose.yaml.dist @@ -21,6 +21,7 @@ services: # service: meilisearch # volumes: # - meilisearch:/meili_data + mysql: extends: # see: https://docs.docker.com/compose/how-tos/multiple-compose-files/extends/ file: ./docker/docker-compose.yaml @@ -42,13 +43,13 @@ services: - XDEBUG_MODE=${PHP_XDEBUG_MODE:-off} - XDEBUG_CONFIG=${PHP_XDEBUG_CONFIG:-client_host=host.docker.internal output_dir=/tmp/xdebug profiler_output_name=cachegrind.out.%R.%u} depends_on: - # - meilisearch + # - meilisearch - mysql - redis - # - soketi + # - soketi volumes: - .:/app - # - $HOME/Development/profiling/${APP_NAME}:/tmp/xdebug # mount xdebug and cachegrind output for profiling analysis on host machine + # - $HOME/Development/profiling/${APP_NAME}:/tmp/xdebug # mount xdebug and cachegrind output for profiling analysis on host machine phpmyadmin: extends: # see: https://docs.docker.com/compose/how-tos/multiple-compose-files/extends/ @@ -89,5 +90,5 @@ volumes: networks: default: - name: "${APP_NAME}-net" + name: '${APP_NAME}-net' driver: bridge From 7c0d10655eef414595fddc93ebb2f5523c55d367 Mon Sep 17 00:00:00 2001 From: Jordy Schreuders <3071062+99linesofcode@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:44:54 +0200 Subject: [PATCH 3/5] docs(readme): improve section on how this is intended to be used --- .env.example | 14 ++------------ README.md | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/.env.example b/.env.example index d254c6a..006e3b2 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,4 @@ -# these variables should be declared in the project root directory -APP_NAME="docker-base" -USER="jordy" -PUID=1000 -PGID=1000 - -PHP_XDEBUG_MODE="develop,debug" -PHP_XDEBUG_CONFIG="client_host=host.docker.internal output_dir=/tmp/xdebug profiler_output_name=cachegrind.out.%R.%u" - -DB_PASSWORD="secret" -DB_USERNAME="default" -DB_DATABASE=${APP_NAME} +# these variables should be declared in your application root .env +APP_NAME="docker-php" CLOUDFLARE_DNS_API_TOKEN="SECRETAPITOKENGOESHERE" diff --git a/README.md b/README.md index e7b6b46..51b2000 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,26 @@ # docker-php -Docker PHP is a collection of services and containers intended to be pulled into a project as a submodule or subtree. It contains all the services necessary to serve a modern Laravel application for development purposes. It's very similar to what Laravel Sail provides but is further configured to suit my personal needs and preferences. +Docker PHP is a collection of services and containers intended to be pulled into a project as a submodule or subtree. It contains all the services necessary to serve a modern Laravel app for development purposes. It's similar to what Laravel Sail provides but is further configured to suit my personal needs and preferences. -Additionally, this repository contains a production ready FrankenPHP container that is preconfigured to automatically request SSL certificates using a Cloudflare DNS challenge when built for production. See the `frankenphp/` subdirectory. +Additionally, this repository contains a production ready FrankenPHP container that's pre-configured to automatically request SSL certificates using a Cloudflare DNS challenge when built for production. See the `frankenphp/` subdirectory. -## Configuration +## How to use -1. Run `git submodule add https://github.com/99linesofcode/docker-php.git docker` from your application root; -1. Copy the `docker-compose.yaml.dist` to the application root; -1. Configure the environment variables defined in the `.env.example` file in your `.env` in the application root; +1. Change to your project root directory (for example: `cd ./laravel-starter`); +1. `git submodule add https://github.com/99linesofcode/docker-php.git docker`; +1. `cp docker/docker-compose.yaml.dist ./docker-compose.yaml`; +1. Configure the environment variables defined in `docker/.env.example` file in your `./.env`; 1. Run `docker compose up -d` to spin up your development environment. Almost all the relevant configuration is done in/from the `docker-compose.yaml` file. Optional services are disabled by default. You can enable these by uncommenting their respective service blocks. ## Production -There are several ways to run Docker PHP in production. Using `docker compose -d` similarly to how you run it in development or by manually building and packaging the application up into a docker image and pushing it to and pulling it from a container registry. +There are several ways to run Docker PHP in production. Using `docker compose -d` similarly to how you run it in development or by manually building and packaging the app up into a docker image and pushing it to and pulling it from a container registry. -The FrankenPHP container uses the multi-stage build process and can be further optimized for production. If you intend to use `docker compose` you will have to change the `services.frankenphp.build.target` to `production`. +The FrankenPHP container uses the multi-stage build process and can be further optimized for production. If you intend to use `docker compose` in production you will have to change the `services.frankenphp.build.target` to `production`. -If you choose to package your application and serve it differently, make sure to pass the `--target production` flag to your `docker build` command like so: `docker build --target production -t frankenphp:production -f ./frankenphp/Dockerfile .`. +If you choose to package your app and serve it differently, make sure to pass the `--target production` flag to your `docker build` command like so: `docker build --target production -t frankenphp:production -f ./frankenphp/Dockerfile .`. ## Contributing From b168bcd1508d79800c136e8c925aa93e815c7e68 Mon Sep 17 00:00:00 2001 From: Jordy Schreuders <3071062+99linesofcode@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:46:22 +0200 Subject: [PATCH 4/5] refactor: mysql and redis containers disabled by default --- docker-compose.yaml.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yaml.dist b/docker-compose.yaml.dist index fbea38c..aecc532 100644 --- a/docker-compose.yaml.dist +++ b/docker-compose.yaml.dist @@ -44,8 +44,8 @@ services: - XDEBUG_CONFIG=${PHP_XDEBUG_CONFIG:-client_host=host.docker.internal output_dir=/tmp/xdebug profiler_output_name=cachegrind.out.%R.%u} depends_on: # - meilisearch - - mysql - - redis + # - mysql + # - redis # - soketi volumes: - .:/app From cdce8f0a8e1554ad43426f719b72e2be6a343bce Mon Sep 17 00:00:00 2001 From: Jordy Schreuders <3071062+99linesofcode@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:57:06 +0200 Subject: [PATCH 5/5] fix: use tab indentation in Caddyfiles --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index 876ec2a..f7a762d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,3 +14,6 @@ trim_trailing_whitespace = false [*.{yml,yaml}] indent_size = 2 + +[Caddyfile] +indent_style = tab