Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
130 changes: 93 additions & 37 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,67 @@ FROM dunglas/frankenphp:1.11-php8.5 AS frankenphp_upstream
# https://docs.docker.com/compose/compose-file/#target


# Base FrankenPHP image
# ---------------------------------------------------------------
# Builder: install prod vendor, dump autoload, warm Symfony cache

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

The comment says this stage "warm[s] Symfony cache", but the stage only runs composer dump-autoload/dump-env and never executes bin/console cache:clear/cache:warmup. Either update the comment to match what’s actually happening, or add an explicit cache warmup step (ideally in the builder so runtime startup doesn’t have to rebuild it).

Suggested change
# Builder: install prod vendor, dump autoload, warm Symfony cache
# Builder: install prod vendor, dump autoload, dump env

Copilot uses AI. Check for mistakes.
# ---------------------------------------------------------------
FROM frankenphp_upstream AS php_builder

WORKDIR /app

ENV COMPOSER_ALLOW_SUPERUSER=1 \
APP_ENV=prod

# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN install-php-extensions \
@composer \
intl \
pdo_mysql \
zip \
;

# Install dependencies first so the layer is cached when only sources change
COPY --link composer.* symfony.* ./
RUN --mount=type=cache,target=/tmp/composer-cache \
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress

COPY --link --exclude=frankenphp/ . ./

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

COPY --exclude=frankenphp/ requires a Dockerfile frontend that supports the --exclude flag; with #syntax=docker/dockerfile:1 this may fail on builders that don't have the newer BuildKit frontend enabled. Consider either bumping the syntax directive to a frontend version that guarantees COPY --exclude support, or avoid --exclude by using .dockerignore/more targeted COPY steps.

Copilot uses AI. Check for mistakes.

RUN set -eux; \
mkdir -p var/cache var/log var/share; \
composer dump-autoload --classmap-authoritative --no-dev; \
composer dump-env prod; \
chmod +x bin/console; \
sync


# ---------------------------------------------------------------
# Builder: compile frontend assets via webpack-encore
# ---------------------------------------------------------------
FROM node:24-alpine AS node_builder

WORKDIR /app

# package.json references "file:vendor/symfony/ux-react/assets"
COPY --from=php_builder /app/vendor ./vendor

COPY --link package.json package-lock.json webpack.config.js tsconfig.json ./
COPY --link assets ./assets

RUN --mount=type=cache,target=/root/.npm \
npm ci --no-audit --no-fund

RUN npm run build


# ---------------------------------------------------------------
# Base FrankenPHP image — minimal, shared by dev and prod
# ---------------------------------------------------------------
FROM frankenphp_upstream AS frankenphp_base

WORKDIR /app
Expand All @@ -18,33 +78,27 @@ VOLUME /app/var/
# persistent / runtime deps
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
file \
cron \
supervisor \
procps \
git \
cron \
file \
procps \
supervisor \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN set -eux; \
install-php-extensions \
@composer \
apcu \
intl \
pdo_mysql \
opcache \
pdo_mysql \
zip \
;

# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
ENV COMPOSER_ALLOW_SUPERUSER=1

ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d"

###> recipes ###
###< recipes ###

RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && apt-get install -y nodejs

COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/
COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
COPY --link frankenphp/Caddyfile /etc/frankenphp/Caddyfile
Expand All @@ -57,26 +111,38 @@ ENTRYPOINT ["docker-entrypoint"]
HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ]

# Dev FrankenPHP image

# ---------------------------------------------------------------
# Dev image — composer + node + git + xdebug for live development
# ---------------------------------------------------------------
FROM frankenphp_base AS frankenphp_dev

ENV APP_ENV=dev
ENV XDEBUG_MODE=off
ENV FRANKENPHP_WORKER_CONFIG=watch
ENV APP_ENV=dev \
XDEBUG_MODE=off \
FRANKENPHP_WORKER_CONFIG=watch \
COMPOSER_ALLOW_SUPERUSER=1

RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# hadolint ignore=DL3008
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
Comment on lines +127 to +129

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

The dev image installs Node.js by piping a remote script into bash (curl ... | bash). This pattern makes builds harder to audit/reproduce and is a supply-chain risk. Prefer installing Node via a pinned, verified package source (or using a dedicated node base image / official Debian packages) to avoid executing unpinned remote code during builds.

Suggested change
&& apt-get install -y --no-install-recommends git \
&& curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& apt-get install -y --no-install-recommends \
git \
nodejs \
npm \

Copilot uses AI. Check for mistakes.
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN set -eux; \
install-php-extensions \
xdebug \
;
RUN install-php-extensions @composer xdebug

RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/
COPY --link frankenphp/supervisord_dev.conf /etc/supervisor/conf.d/supervisord.conf

CMD ["/usr/bin/supervisord"]

# Prod FrankenPHP image

# ---------------------------------------------------------------
# Prod image — minimal runtime, pre-built vendor + assets
# ---------------------------------------------------------------
FROM frankenphp_base AS frankenphp_prod

ENV APP_ENV=prod
Expand All @@ -85,21 +151,11 @@ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

COPY --link frankenphp/conf.d/20-app.prod.ini $PHP_INI_DIR/app.conf.d/

# prevent the reinstallation of vendors at every changes in the source code
COPY --link composer.* symfony.* ./
RUN set -eux; \
composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress
# Pre-built application: vendor, sources, warmed cache, bundle assets
COPY --from=php_builder --link /app /app
# Pre-built webpack assets
COPY --from=node_builder --link /app/public/build /app/public/build

# copy sources
COPY --link --exclude=frankenphp/ . ./
COPY --link frankenphp/supervisord_prod.conf /etc/supervisor/conf.d/supervisord.conf

RUN set -eux
RUN mkdir -p var/cache var/log var/share
RUN composer dump-autoload --classmap-authoritative --no-dev
RUN composer dump-env prod
#RUN composer run-script --no-dev post-install-cmd
RUN chmod +x bin/console
RUN sync

CMD ["/usr/bin/supervisord"]
11 changes: 7 additions & 4 deletions frankenphp/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#!/bin/sh
set -e

if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then
if command -v composer >/dev/null 2>&1 && [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then
composer install --prefer-dist --no-progress --no-interaction
fi

npm install
npm run build
if command -v npm >/dev/null 2>&1; then
npm install
npm run build
fi

# Display information about the current project
# Or about an error in project initialization
Expand Down Expand Up @@ -38,7 +40,8 @@ if grep -q ^DATABASE_URL= .env; then
fi
fi

composer run-script --no-dev post-install-cmd
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug

Comment on lines +43 to 45

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

cache:clear and assets:install are always executed with --no-debug. In the dev image APP_ENV=dev and APP_DEBUG is typically on; forcing --no-debug here can generate a cache that doesn’t match the runtime debug setting and can make debugging behavior inconsistent. Consider making --no-debug conditional on APP_ENV=prod (or using the current APP_DEBUG value) instead of hard-coding it.

Suggested change
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug
NO_DEBUG_FLAG=''
if [ "${APP_ENV:-}" = 'prod' ] || [ "${APP_DEBUG:-}" = '0' ] || [ "${APP_DEBUG:-}" = 'false' ]; then
NO_DEBUG_FLAG='--no-debug'
fi
php bin/console cache:clear ${NO_DEBUG_FLAG}
php bin/console assets:install public ${NO_DEBUG_FLAG}

Copilot uses AI. Check for mistakes.
Comment on lines +43 to 45

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

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

This entrypoint clears the Symfony cache and installs bundle assets on every container start. With the new multi-stage build (pre-built vendor/assets), doing this work at runtime increases startup time and reduces the benefit of building/warming once during the image build. Consider moving these steps into the php_builder stage for frankenphp_prod, or guarding them (e.g., only when the cache/assets directories are missing or behind an env flag).

Suggested change
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug
RUN_SYMFONY_RUNTIME_SETUP="${RUN_SYMFONY_RUNTIME_SETUP:-0}"
if [ "$RUN_SYMFONY_RUNTIME_SETUP" = "1" ] || [ -z "$(ls -A 'var/cache/' 2>/dev/null)" ]; then
php bin/console cache:clear --no-debug
fi
if [ "$RUN_SYMFONY_RUNTIME_SETUP" = "1" ] || [ -z "$(ls -A 'public/bundles/' 2>/dev/null)" ]; then
php bin/console assets:install public --no-debug
fi

Copilot uses AI. Check for mistakes.
echo 'PHP app ready!'

Expand Down
Loading