Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,10 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Test nginx config
run: docker run --rm -i "$TEST_TAG" nginx -t
- name: Test php-fpm config
run: docker run --rm -i "$TEST_TAG" php-fpm -tt
- name: Test RoadRunner
run: docker run --rm -i "$TEST_TAG" rr --version
- name: Test commands exist
run: docker run --rm -i "$TEST_TAG" which composer install-php-extensions clevyr-build
run: docker run --rm -i "$TEST_TAG" which composer install-php-extensions clevyr-build rr

- name: Build and Push (base)
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
Expand Down
59 changes: 11 additions & 48 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,17 @@
ARG COMPOSER_VERSION
ARG ALPINE_VERSION

FROM composer:$COMPOSER_VERSION AS local-composer

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.5-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.3-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.4-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.1-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.2-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.2-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 7 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.2-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG composer:$COMPOSER_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

FROM php:$PHP_VERSION-fpm-alpine$ALPINE_VERSION AS base
WORKDIR /app
FROM php:$PHP_VERSION-cli-alpine$ALPINE_VERSION AS base

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.5-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.3-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.4-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.1-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.2-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.2-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 9 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build 8.2-composer2

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG php:$PHP_VERSION-cli-alpine$ALPINE_VERSION results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

COPY --from=mlocati/php-extension-installer:2.10.6 /usr/bin/install-php-extensions /usr/bin/

RUN <<EOT
set -eux
apk add --no-cache bash fcgi gettext git jq nginx postgresql-client s6 su-exec
apk add --no-cache bash git jq postgresql-client s6
install-php-extensions bcmath calendar exif intl pcntl opcache pgsql pdo_pgsql redis zip
cd "$PHP_INI_DIR"
sed -ri -e 's/^(access.log)/;\1/' ../php-fpm.d/docker.conf
sed -ri \
-e 's/^;(ping\.path)/\1/' \
-e 's/^;(pm\.status_path)/\1/' \
-e 's/^;?(pm\.max_children).*/\1 = ${PHP_FPM_PM_MAX_CHILDREN}/' \
-e 's/^;?(pm\.start_servers).*/\1 = ${PHP_FPM_PM_START_SERVERS}/' \
-e 's/^;?(pm\.min_spare_servers).*/\1 = ${PHP_FPM_PM_MIN_SPARE_SERVERS}/' \
-e 's/^;?(pm\.max_spare_servers).*/\1 = ${PHP_FPM_PM_MAX_SPARE_SERVERS}/' \
-e 's/^;?(pm\.max_requests).*/\1 = ${PHP_FPM_PM_MAX_REQUESTS}/' \
../php-fpm.d/www.conf
sed -ri \
-e 's/^;?(max_execution_time).*/\1 = ${PHP_MAX_EXECUTION_TIME}/' \
-e 's/^;?(max_input_vars).*/\1 = ${PHP_MAX_INPUT_VARS}/' \
Expand All @@ -36,30 +25,10 @@
-e 's/^;?(expose_php).*/\1 = Off/' \
php.ini-production
ln -s php.ini-production php.ini
mkdir -p /run/nginx
sed -ri -e 's/#(tcp_nopush on;)/\1/' /etc/nginx/nginx.conf
if [ -d /etc/nginx/http.d ]; then
mv /etc/nginx/http.d /etc/nginx/conf.d
sed -ri \
-e 's|/etc/nginx/http.d|/etc/nginx/conf.d|' \
-e 's|^include /etc/nginx/conf.d/\*.conf;||' \
/etc/nginx/nginx.conf
fi
EOT

ENV LC_ALL=C

ARG PHP_FPM_PM_MAX_CHILDREN=80
ENV PHP_FPM_PM_MAX_CHILDREN=$PHP_FPM_PM_MAX_CHILDREN
ARG PHP_FPM_PM_START_SERVERS=2
ENV PHP_FPM_PM_START_SERVERS=$PHP_FPM_PM_START_SERVERS
ARG PHP_FPM_PM_MIN_SPARE_SERVERS=1
ENV PHP_FPM_PM_MIN_SPARE_SERVERS=$PHP_FPM_PM_MIN_SPARE_SERVERS
ARG PHP_FPM_PM_MAX_SPARE_SERVERS=3
ENV PHP_FPM_PM_MAX_SPARE_SERVERS=$PHP_FPM_PM_MAX_SPARE_SERVERS
ARG PHP_FPM_PM_MAX_REQUESTS=0
ENV PHP_FPM_PM_MAX_REQUESTS=$PHP_FPM_PM_MAX_REQUESTS

ARG PHP_MAX_EXECUTION_TIME=30
ENV PHP_MAX_EXECUTION_TIME=$PHP_MAX_EXECUTION_TIME
ARG PHP_MAX_INPUT_VARS=1000
Expand Down Expand Up @@ -89,21 +58,13 @@
COPY --from=ghcr.io/roadrunner-server/roadrunner:2025.1.11 /usr/bin/rr /usr/local/bin/rr
COPY rootfs/ /

CMD ["s6-svscan", "/etc/services.d"]
USER nobody:nogroup
WORKDIR /app

CMD ["s6-svscan-rootless", "/etc/services.d"]

FROM base AS onbuild

ONBUILD ARG PHP_FPM_PM_MAX_CHILDREN
ONBUILD ENV PHP_FPM_PM_MAX_CHILDREN=${PHP_FPM_PM_MAX_CHILDREN:-20}
ONBUILD ARG PHP_FPM_PM_START_SERVERS
ONBUILD ENV PHP_FPM_PM_START_SERVERS=${PHP_FPM_PM_START_SERVERS:-2}
ONBUILD ARG PHP_FPM_PM_MIN_SPARE_SERVERS
ONBUILD ENV PHP_FPM_PM_MIN_SPARE_SERVERS=${PHP_FPM_PM_MIN_SPARE_SERVERS:-1}
ONBUILD ARG PHP_FPM_PM_MAX_SPARE_SERVERS
ONBUILD ENV PHP_FPM_PM_MAX_SPARE_SERVERS=${PHP_FPM_PM_MAX_SPARE_SERVERS:-3}
ONBUILD ARG PHP_FPM_PM_MAX_REQUESTS
ONBUILD ENV PHP_FPM_PM_MAX_REQUESTS=${PHP_FPM_PM_MAX_REQUESTS:-0}

ONBUILD ARG PHP_MAX_EXECUTION_TIME
ONBUILD ENV PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME:-30}
ONBUILD ARG PHP_MAX_INPUT_VARS
Expand All @@ -125,19 +86,21 @@
ONBUILD ARG INSTALL_IMAGICK
ONBUILD ARG INSTALL_MOSQUITTO
ONBUILD ARG INSTALL_MYSQL
ONBUILD ARG INSTALL_SOCKETS=true
ONBUILD ARG INSTALL_SQLSRV
ONBUILD ARG INSTALL_XDEBUG

ONBUILD ARG NGINX_ROOT
ONBUILD ARG NGINX_EXPIRES

ONBUILD ARG COMPOSER_VERSION

ONBUILD ARG IPE_GD_WITHOUTAVIF=1

ONBUILD USER root

ONBUILD RUN <<EOT
set -eux
if [ "${SKIP_BUILD:-}" != "true" ]; then
clevyr-build
fi
EOT

ONBUILD USER nobody:nogroup
21 changes: 1 addition & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Docker Build](https://github.com/clevyr/docker-php/actions/workflows/docker.yml/badge.svg)](https://github.com/clevyr/docker-php/actions/workflows/docker.yml)

An enhanced version of the default [PHP Docker image](https://hub.docker.com/_/php) which can install PHP extensions without requiring manual dependency installation using [mlocati/docker-php-extension-installer](https://github.com/mlocati/docker-php-extension-installer) and installs a default nginx setup.
An enhanced version of the default [PHP Docker image](https://hub.docker.com/_/php) which can install PHP extensions without requiring manual dependency installation using [mlocati/docker-php-extension-installer](https://github.com/mlocati/docker-php-extension-installer).

## Pull Command

Expand All @@ -29,16 +29,6 @@ Some php.ini values can be configured as a build arg.
| `PHP_UPLOAD_MAX_FILESIZE` | See [`upload_max_filesize`](https://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize). | `8M` |
| `PHP_MAX_FILE_UPLOADS` | See [`max_file_uploads`](https://www.php.net/manual/en/ini.core.php#ini.max-file-uploads). | `20` |

### PHP-FPM Configuration

| Environment Variable | Description | Default |
|--------------------------------|-----------------------------------------------------------------------------------------------------------------|---------|
| `PHP_FPM_PM_MAX_CHILDREN` | See [`pm.max_children`](https://www.php.net/manual/en/install.fpm.configuration.php#pm.max-children). | `80` |
| `PHP_FPM_PM_START_SERVERS` | See [`pm.start_servers`](https://www.php.net/manual/en/install.fpm.configuration.php#pm.start-servers). | `2` |
| `PHP_FPM_PM_MIN_SPARE_SERVERS` | See [`pm.min_spare_servers`](https://www.php.net/manual/en/install.fpm.configuration.php#pm.min-spare-servers). | `1` |
| `PHP_FPM_PM_MAX_SPARE_SERVERS` | See [`pm.max_spare_servers`](https://www.php.net/manual/en/install.fpm.configuration.php#pm.max-spare-servers). | `3` |
| `PHP_FPM_PM_MAX_REQUESTS` | See [`pm.max_requests`](https://www.php.net/manual/en/install.fpm.configuration.php#pm.max-requests). | `0` |

## Build Arguments

The following variables can be only be configured at build.
Expand All @@ -48,15 +38,6 @@ The following variables can be only be configured at build.
| `INSTALL` | PHP extensions to install. See [here](https://github.com/mlocati/docker-php-extension-installer#supported-php-extensions) for available extensions. |
| `DEPS` | `apk` dependencies to install during the build. |

### Nginx Configuration

Some nginx values can be configured as a build arg.

| Build Arg | Nginx Directive | Default |
|-----------------|-------------------------------------------------------------------------------|---------------|
| `NGINX_ROOT` | [root](http://nginx.org/en/docs/http/ngx_http_core_module.html#root) | `/app/public` |
| `NGINX_EXPIRES` | [expires](http://nginx.org/en/docs/http/ngx_http_headers_module.html#expires) | `7d` |

### Legacy Build Arguments

These are the legacy build args. They will still be supported for the forseeable future, but they are not as powerful as the new `INSTALL` build arg, so if you are creating an app from scratch, the `INSTALL` build arg may be more useful for you. These are also convenient because they group up some extensnions. For example, if you set `INSTALL_MYSQL=true`, then both `mysqli` and `pdo_mysql` will be installed.
Expand Down
6 changes: 0 additions & 6 deletions rootfs/entrypoint

This file was deleted.

3 changes: 0 additions & 3 deletions rootfs/etc/nginx/conf.d/0-gzip.conf

This file was deleted.

49 changes: 0 additions & 49 deletions rootfs/etc/nginx/conf.d/default.conf.tpl

This file was deleted.

3 changes: 0 additions & 3 deletions rootfs/etc/services.d/nginx/run

This file was deleted.

3 changes: 0 additions & 3 deletions rootfs/etc/services.d/php-fpm/run

This file was deleted.

17 changes: 3 additions & 14 deletions rootfs/health-check
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,7 @@

set -e

if [ -n "$1" ]; then
export HEALTH_CHECK_IP="$1"
fi
HEALTH_CHECK_HOST="${1:-127.0.0.1}"
HEALTH_CHECK_PORT="${2:-2114}"

if [ -n "$2" ]; then
export HEALTH_CHECK_PORT="$2"
fi

env -i REDIRECT_STATUS=true \
SCRIPT_NAME=/ping \
SCRIPT_FILENAME=/ping \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect \
"${HEALTH_CHECK_IP:-127.0.0.1}:${HEALTH_CHECK_PORT:-9000}" \
| grep -e pong >/dev/null
wget -qO /dev/null "http://${HEALTH_CHECK_HOST}:${HEALTH_CHECK_PORT}/health?plugin=http"
6 changes: 0 additions & 6 deletions rootfs/usr/bin/clevyr-build
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,5 @@ fi
log "Beginning install: ${INSTALL[*]}"
install-php-extensions "${INSTALL[@]}"

# Template nginx config
log 'Templating nginx config'
export NGINX_ROOT="${NGINX_ROOT:-/app/public}" \
NGINX_EXPIRES="${NGINX_EXPIRES:-7d}"
envsubst '$NGINX_ROOT $NGINX_EXPIRES' < /etc/nginx/conf.d/default.conf.tpl > /etc/nginx/conf.d/default.conf

log 'Removing all tmp files'
rm -rf /tmp/*
5 changes: 0 additions & 5 deletions rootfs/usr/bin/clevyr-php-pre-stop

@USA-RedDragon USA-RedDragon Apr 17, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we no longer need this as RoadRunner should gracefully handle SIGTERM for shutdown: https://docs.roadrunner.dev/docs/app-server/cli#stopping-the-server.

This file was deleted.

15 changes: 0 additions & 15 deletions rootfs/usr/bin/php-fpm-status

This file was deleted.

25 changes: 25 additions & 0 deletions rootfs/usr/bin/s6-svscan-rootless
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/sh

set -euo pipefail

# Wrapper to run s6-svscan from a writable directory
# s6-svscan creates .s6-svscan in the service directory, so we need to copy services to /tmp

# See https://skarnet.org/software/s6/scandir.html

SERVICE_DIR="$1"

if [ -z "$SERVICE_DIR" ]; then
echo "Usage: $0 <service-directory>" >&2
exit 1
fi

# Create a unique directory in /tmp for our services
TEMP_SERVICE_DIR="/tmp/s6-services-$$"
mkdir -p "$TEMP_SERVICE_DIR"

# Copy the service directory contents to /tmp
cp -r "$SERVICE_DIR"/* "$TEMP_SERVICE_DIR/" 2>/dev/null || cp -r "$SERVICE_DIR"/. "$TEMP_SERVICE_DIR/"

# Run s6-svscan against the copied services
exec s6-svscan "$TEMP_SERVICE_DIR"
Loading