diff --git a/Dockerfile b/Dockerfile
index 85536666..b9080886 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,133 +1,91 @@
-FROM debian:bullseye-slim
+#syntax=docker/dockerfile:1.4
-# Install needed dependencies for PHP build
-#RUN apt-get update && apt-get install -y pkg-config curl libcurl4-openssl-dev libicu-dev \
-# libpng-dev libjpeg-dev libfreetype6-dev gnupg zip libzip-dev libjpeg62-turbo-dev libonig-dev libxslt-dev libwebp-dev vim \
-# && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*
+# Versions
+FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream
-RUN apt-get update && apt-get -y install apt-transport-https lsb-release ca-certificates curl zip mariadb-client \
- && curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg \
- && sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list' \
- && apt-get update && apt-get upgrade -y \
- && apt-get install -y apache2 php8.1 php8.1-fpm php8.1-opcache php8.1-curl php8.1-gd php8.1-mbstring php8.1-xml php8.1-bcmath php8.1-intl php8.1-zip php8.1-xsl php8.1-sqlite3 php8.1-mysql gpg \
- && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*;
-
-ENV APACHE_CONFDIR /etc/apache2
-ENV APACHE_ENVVARS $APACHE_CONFDIR/envvars
-
-# Create workdir and set permissions if directory does not exists
-RUN mkdir -p /var/www/html && chown -R www-data:www-data /var/www/html
-
-# Configure apache 2 (taken from https://github.com/docker-library/php/blob/master/8.2/bullseye/apache/Dockerfile)
-# generically convert lines like
-# export APACHE_RUN_USER=www-data
-# into
-# : ${APACHE_RUN_USER:=www-data}
-# export APACHE_RUN_USER
-# so that they can be overridden at runtime ("-e APACHE_RUN_USER=...")
-RUN sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS"; \
- set -eux; . "$APACHE_ENVVARS"; \
- # delete the "index.html" that installing Apache drops in here
- rm -rvf /var/www/html/*; \
- \
- # logs should go to stdout / stderr
- ln -sfT /dev/stderr "$APACHE_LOG_DIR/error.log"; \
- ln -sfT /dev/stdout "$APACHE_LOG_DIR/access.log"; \
- ln -sfT /dev/stdout "$APACHE_LOG_DIR/other_vhosts_access.log"; \
- chown -R --no-dereference "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$APACHE_LOG_DIR";
-
-# Enable php-fpm
-RUN a2enmod proxy_fcgi setenvif && a2enconf php8.1-fpm
-
-# Configure php-fpm to log to stdout of the container (stdout of PID 1)
-# We have to use /proc/1/fd/1 because /dev/stdout or /proc/self/fd/1 does not point to the container stdout (because we use apache as entrypoint)
-# We also disable the clear_env option to allow the use of environment variables in php-fpm
-RUN { \
- echo '[global]'; \
- echo 'error_log = /proc/1/fd/1'; \
- echo; \
- echo '[www]'; \
- echo 'access.log = /proc/1/fd/1'; \
- echo 'catch_workers_output = yes'; \
- echo 'decorate_workers_output = no'; \
- echo 'clear_env = no'; \
- } | tee "/etc/php/8.1/fpm/pool.d/zz-docker.conf"
-
-# PHP files should be handled by PHP, and should be preferred over any other file type
-RUN { \
- echo ''; \
- echo '\tSetHandler application/x-httpd-php'; \
- echo ''; \
- echo; \
- echo 'DirectoryIndex disabled'; \
- echo 'DirectoryIndex index.php index.html'; \
- echo; \
- echo ''; \
- echo '\tOptions -Indexes'; \
- echo '\tAllowOverride All'; \
- echo ''; \
- } | tee "$APACHE_CONFDIR/conf-available/docker-php.conf" \
- && a2enconf docker-php
-
-# Enable opcache and configure it recommended for symfony (see https://symfony.com/doc/current/performance.html)
-RUN \
- { \
- echo 'opcache.memory_consumption=256'; \
- echo 'opcache.max_accelerated_files=20000'; \
- echo 'opcache.validate_timestamp=0'; \
- # Configure Realpath cache for performance
- echo 'realpath_cache_size=4096K'; \
- echo 'realpath_cache_ttl=600'; \
- } > /etc/php/8.1/fpm/conf.d/symfony-recommended.ini
-
-# Increase upload limit and enable preloading
-RUN \
- { \
- echo 'upload_max_filesize=256M'; \
- echo 'post_max_size=300M'; \
- echo 'opcache.preload_user=www-data'; \
- echo 'opcache.preload=/var/www/html/config/preload.php'; \
- } > /etc/php/8.1/fpm/conf.d/partdb.ini
-
-# Install node and yarn
-RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
-RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
-RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get update && apt-get install -y nodejs yarn && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*
-
-# Install composer
-COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
+# The different stages of this Dockerfile are meant to be built into separate images
+# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
+# https://docs.docker.com/compose/compose-file/#target
-# Set working dir
-WORKDIR /var/www/html
-COPY --chown=www-data:www-data . .
+# Base FrankenPHP image
+FROM frankenphp_upstream AS frankenphp_base
-# Setup apache2
-RUN a2dissite 000-default.conf
-COPY ./.docker/symfony.conf /etc/apache2/sites-available/symfony.conf
-RUN a2ensite symfony.conf
-RUN a2enmod rewrite
+WORKDIR /app
-# Install composer and yarn dependencies for Part-DB
-USER www-data
-RUN composer install -a --no-dev && composer clear-cache
-RUN yarn install --network-timeout 600000 && yarn build && yarn cache clean && rm -rf node_modules/
+# persistent / runtime deps
+# hadolint ignore=DL3008
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ acl \
+ file \
+ gettext \
+ git \
+ && rm -rf /var/lib/apt/lists/*
-# Use docker env to output logs to stdout
-ENV APP_ENV=docker
-ENV DATABASE_URL="sqlite:///%kernel.project_dir%/uploads/app.db"
+RUN set -eux; \
+ install-php-extensions \
+ @composer \
+ apcu \
+ intl \
+ opcache \
+ zip \
+ ;
-USER root
+# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
+ENV COMPOSER_ALLOW_SUPERUSER=1
-# Copy entrypoint to /usr/local/bin and make it executable
-RUN cp ./.docker/partdb-entrypoint.sh /usr/local/bin/partdb-entrypoint.sh && chmod +x /usr/local/bin/partdb-entrypoint.sh
-# Copy apache2-foreground to /usr/local/bin and make it executable
-RUN cp ./.docker/apache2-foreground /usr/local/bin/apache2-foreground && chmod +x /usr/local/bin/apache2-foreground
-ENTRYPOINT ["partdb-entrypoint.sh"]
-CMD ["apache2-foreground"]
+###> recipes ###
+###< recipes ###
-# https://httpd.apache.org/docs/2.4/stopping.html#gracefulstop
-STOPSIGNAL SIGWINCH
+COPY --link frankenphp/conf.d/app.ini $PHP_INI_DIR/conf.d/
+COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
+COPY --link frankenphp/Caddyfile /etc/caddy/Caddyfile
-EXPOSE 80
-VOLUME ["/var/www/html/uploads", "/var/www/html/public/media"]
\ No newline at end of file
+ENTRYPOINT ["docker-entrypoint"]
+
+HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1
+CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ]
+
+# Dev FrankenPHP image
+FROM frankenphp_base AS frankenphp_dev
+
+ENV APP_ENV=dev XDEBUG_MODE=off
+VOLUME /app/var/
+
+RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
+
+RUN set -eux; \
+ install-php-extensions \
+ xdebug \
+ ;
+
+COPY --link frankenphp/conf.d/app.dev.ini $PHP_INI_DIR/conf.d/
+
+CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ]
+
+# Prod FrankenPHP image
+FROM frankenphp_base AS frankenphp_prod
+
+ENV APP_ENV=prod
+ENV FRANKENPHP_CONFIG="import worker.Caddyfile"
+
+RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
+
+COPY --link frankenphp/conf.d/app.prod.ini $PHP_INI_DIR/conf.d/
+COPY --link frankenphp/worker.Caddyfile /etc/caddy/worker.Caddyfile
+
+# 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
+
+# copy sources
+COPY --link . ./
+RUN rm -Rf frankenphp/
+
+RUN set -eux; \
+ mkdir -p var/cache var/log; \
+ composer dump-autoload --classmap-authoritative --no-dev; \
+ composer dump-env prod; \
+ composer run-script --no-dev post-install-cmd; \
+ chmod +x bin/console; sync;
diff --git a/Dockerfile.old b/Dockerfile.old
new file mode 100644
index 00000000..85536666
--- /dev/null
+++ b/Dockerfile.old
@@ -0,0 +1,133 @@
+FROM debian:bullseye-slim
+
+# Install needed dependencies for PHP build
+#RUN apt-get update && apt-get install -y pkg-config curl libcurl4-openssl-dev libicu-dev \
+# libpng-dev libjpeg-dev libfreetype6-dev gnupg zip libzip-dev libjpeg62-turbo-dev libonig-dev libxslt-dev libwebp-dev vim \
+# && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*
+
+RUN apt-get update && apt-get -y install apt-transport-https lsb-release ca-certificates curl zip mariadb-client \
+ && curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg \
+ && sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list' \
+ && apt-get update && apt-get upgrade -y \
+ && apt-get install -y apache2 php8.1 php8.1-fpm php8.1-opcache php8.1-curl php8.1-gd php8.1-mbstring php8.1-xml php8.1-bcmath php8.1-intl php8.1-zip php8.1-xsl php8.1-sqlite3 php8.1-mysql gpg \
+ && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*;
+
+ENV APACHE_CONFDIR /etc/apache2
+ENV APACHE_ENVVARS $APACHE_CONFDIR/envvars
+
+# Create workdir and set permissions if directory does not exists
+RUN mkdir -p /var/www/html && chown -R www-data:www-data /var/www/html
+
+# Configure apache 2 (taken from https://github.com/docker-library/php/blob/master/8.2/bullseye/apache/Dockerfile)
+# generically convert lines like
+# export APACHE_RUN_USER=www-data
+# into
+# : ${APACHE_RUN_USER:=www-data}
+# export APACHE_RUN_USER
+# so that they can be overridden at runtime ("-e APACHE_RUN_USER=...")
+RUN sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS"; \
+ set -eux; . "$APACHE_ENVVARS"; \
+ # delete the "index.html" that installing Apache drops in here
+ rm -rvf /var/www/html/*; \
+ \
+ # logs should go to stdout / stderr
+ ln -sfT /dev/stderr "$APACHE_LOG_DIR/error.log"; \
+ ln -sfT /dev/stdout "$APACHE_LOG_DIR/access.log"; \
+ ln -sfT /dev/stdout "$APACHE_LOG_DIR/other_vhosts_access.log"; \
+ chown -R --no-dereference "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$APACHE_LOG_DIR";
+
+# Enable php-fpm
+RUN a2enmod proxy_fcgi setenvif && a2enconf php8.1-fpm
+
+# Configure php-fpm to log to stdout of the container (stdout of PID 1)
+# We have to use /proc/1/fd/1 because /dev/stdout or /proc/self/fd/1 does not point to the container stdout (because we use apache as entrypoint)
+# We also disable the clear_env option to allow the use of environment variables in php-fpm
+RUN { \
+ echo '[global]'; \
+ echo 'error_log = /proc/1/fd/1'; \
+ echo; \
+ echo '[www]'; \
+ echo 'access.log = /proc/1/fd/1'; \
+ echo 'catch_workers_output = yes'; \
+ echo 'decorate_workers_output = no'; \
+ echo 'clear_env = no'; \
+ } | tee "/etc/php/8.1/fpm/pool.d/zz-docker.conf"
+
+# PHP files should be handled by PHP, and should be preferred over any other file type
+RUN { \
+ echo ''; \
+ echo '\tSetHandler application/x-httpd-php'; \
+ echo ''; \
+ echo; \
+ echo 'DirectoryIndex disabled'; \
+ echo 'DirectoryIndex index.php index.html'; \
+ echo; \
+ echo ''; \
+ echo '\tOptions -Indexes'; \
+ echo '\tAllowOverride All'; \
+ echo ''; \
+ } | tee "$APACHE_CONFDIR/conf-available/docker-php.conf" \
+ && a2enconf docker-php
+
+# Enable opcache and configure it recommended for symfony (see https://symfony.com/doc/current/performance.html)
+RUN \
+ { \
+ echo 'opcache.memory_consumption=256'; \
+ echo 'opcache.max_accelerated_files=20000'; \
+ echo 'opcache.validate_timestamp=0'; \
+ # Configure Realpath cache for performance
+ echo 'realpath_cache_size=4096K'; \
+ echo 'realpath_cache_ttl=600'; \
+ } > /etc/php/8.1/fpm/conf.d/symfony-recommended.ini
+
+# Increase upload limit and enable preloading
+RUN \
+ { \
+ echo 'upload_max_filesize=256M'; \
+ echo 'post_max_size=300M'; \
+ echo 'opcache.preload_user=www-data'; \
+ echo 'opcache.preload=/var/www/html/config/preload.php'; \
+ } > /etc/php/8.1/fpm/conf.d/partdb.ini
+
+# Install node and yarn
+RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
+RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
+RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get update && apt-get install -y nodejs yarn && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*
+
+# Install composer
+COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
+
+
+# Set working dir
+WORKDIR /var/www/html
+COPY --chown=www-data:www-data . .
+
+# Setup apache2
+RUN a2dissite 000-default.conf
+COPY ./.docker/symfony.conf /etc/apache2/sites-available/symfony.conf
+RUN a2ensite symfony.conf
+RUN a2enmod rewrite
+
+# Install composer and yarn dependencies for Part-DB
+USER www-data
+RUN composer install -a --no-dev && composer clear-cache
+RUN yarn install --network-timeout 600000 && yarn build && yarn cache clean && rm -rf node_modules/
+
+# Use docker env to output logs to stdout
+ENV APP_ENV=docker
+ENV DATABASE_URL="sqlite:///%kernel.project_dir%/uploads/app.db"
+
+USER root
+
+# Copy entrypoint to /usr/local/bin and make it executable
+RUN cp ./.docker/partdb-entrypoint.sh /usr/local/bin/partdb-entrypoint.sh && chmod +x /usr/local/bin/partdb-entrypoint.sh
+# Copy apache2-foreground to /usr/local/bin and make it executable
+RUN cp ./.docker/apache2-foreground /usr/local/bin/apache2-foreground && chmod +x /usr/local/bin/apache2-foreground
+ENTRYPOINT ["partdb-entrypoint.sh"]
+CMD ["apache2-foreground"]
+
+# https://httpd.apache.org/docs/2.4/stopping.html#gracefulstop
+STOPSIGNAL SIGWINCH
+
+EXPOSE 80
+VOLUME ["/var/www/html/uploads", "/var/www/html/public/media"]
\ No newline at end of file
diff --git a/compose.override.yaml b/compose.override.yaml
new file mode 100644
index 00000000..5f141b1f
--- /dev/null
+++ b/compose.override.yaml
@@ -0,0 +1,24 @@
+# Development environment override
+services:
+ php:
+ build:
+ context: .
+ target: frankenphp_dev
+ volumes:
+ - ./:/app
+ - ./frankenphp/Caddyfile:/etc/caddy/Caddyfile:ro
+ - ./frankenphp/conf.d/app.dev.ini:/usr/local/etc/php/conf.d/app.dev.ini:ro
+ # If you develop on Mac or Windows you can remove the vendor/ directory
+ # from the bind-mount for better performance by enabling the next line:
+ #- /app/vendor
+ environment:
+ MERCURE_EXTRA_DIRECTIVES: demo
+ # See https://xdebug.org/docs/all_settings#mode
+ XDEBUG_MODE: "${XDEBUG_MODE:-off}"
+ extra_hosts:
+ # Ensure that host.docker.internal is correctly defined on Linux
+ - host.docker.internal:host-gateway
+ tty: true
+
+###> symfony/mercure-bundle ###
+###< symfony/mercure-bundle ###
diff --git a/compose.prod.yaml b/compose.prod.yaml
new file mode 100644
index 00000000..f0db05da
--- /dev/null
+++ b/compose.prod.yaml
@@ -0,0 +1,10 @@
+# Production environment override
+services:
+ php:
+ build:
+ context: .
+ target: frankenphp_prod
+ environment:
+ APP_SECRET: ${APP_SECRET}
+ MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
+ MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 00000000..43a07900
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,45 @@
+services:
+ php:
+ image: ${IMAGES_PREFIX:-}app-php
+ restart: unless-stopped
+ environment:
+ SERVER_NAME: ${SERVER_NAME:-localhost}, php:80
+ MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
+ MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
+ TRUSTED_PROXIES: ${TRUSTED_PROXIES:-127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}
+ TRUSTED_HOSTS: ^${SERVER_NAME:-example\.com|localhost}|php$$
+ # Run "composer require symfony/orm-pack" to install and configure Doctrine ORM
+ DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-15}&charset=${POSTGRES_CHARSET:-utf8}
+ # Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration
+ MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure}
+ MERCURE_PUBLIC_URL: https://${SERVER_NAME:-localhost}/.well-known/mercure
+ MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
+ # The two next lines can be removed after initial installation
+ SYMFONY_VERSION: ${SYMFONY_VERSION:-}
+ STABILITY: ${STABILITY:-stable}
+ volumes:
+ - caddy_data:/data
+ - caddy_config:/config
+ ports:
+ # HTTP
+ - target: 80
+ published: ${HTTP_PORT:-80}
+ protocol: tcp
+ # HTTPS
+ - target: 443
+ published: ${HTTPS_PORT:-443}
+ protocol: tcp
+ # HTTP/3
+ - target: 443
+ published: ${HTTP3_PORT:-443}
+ protocol: udp
+
+# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service
+###> symfony/mercure-bundle ###
+###< symfony/mercure-bundle ###
+
+volumes:
+ caddy_data:
+ caddy_config:
+###> symfony/mercure-bundle ###
+###< symfony/mercure-bundle ###
diff --git a/frankenphp/Caddyfile b/frankenphp/Caddyfile
new file mode 100644
index 00000000..83839304
--- /dev/null
+++ b/frankenphp/Caddyfile
@@ -0,0 +1,55 @@
+{
+ {$CADDY_GLOBAL_OPTIONS}
+
+ frankenphp {
+ {$FRANKENPHP_CONFIG}
+ }
+
+ # https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
+ order mercure after encode
+ order vulcain after reverse_proxy
+ order php_server before file_server
+}
+
+{$CADDY_EXTRA_CONFIG}
+
+{$SERVER_NAME:localhost} {
+ log {
+ # Redact the authorization query parameter that can be set by Mercure
+ format filter {
+ wrap console
+ fields {
+ uri query {
+ replace authorization REDACTED
+ }
+ }
+ }
+ }
+
+ root * /app/public
+ encode zstd br gzip
+
+ mercure {
+ # Transport to use (default to Bolt)
+ transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
+ # Publisher JWT key
+ publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
+ # Subscriber JWT key
+ subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
+ # Allow anonymous subscribers (double-check that it's what you want)
+ anonymous
+ # Enable the subscription API (double-check that it's what you want)
+ subscriptions
+ # Extra directives
+ {$MERCURE_EXTRA_DIRECTIVES}
+ }
+
+ vulcain
+
+ {$CADDY_SERVER_EXTRA_DIRECTIVES}
+
+ # Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
+ header ?Permissions-Policy "browsing-topics=()"
+
+ php_server
+}
diff --git a/frankenphp/conf.d/app.dev.ini b/frankenphp/conf.d/app.dev.ini
new file mode 100644
index 00000000..e50f43d0
--- /dev/null
+++ b/frankenphp/conf.d/app.dev.ini
@@ -0,0 +1,5 @@
+; See https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host
+; See https://github.com/docker/for-linux/issues/264
+; The `client_host` below may optionally be replaced with `discover_client_host=yes`
+; Add `start_with_request=yes` to start debug session on each request
+xdebug.client_host = host.docker.internal
diff --git a/frankenphp/conf.d/app.ini b/frankenphp/conf.d/app.ini
new file mode 100644
index 00000000..79a17dd8
--- /dev/null
+++ b/frankenphp/conf.d/app.ini
@@ -0,0 +1,13 @@
+expose_php = 0
+date.timezone = UTC
+apc.enable_cli = 1
+session.use_strict_mode = 1
+zend.detect_unicode = 0
+
+; https://symfony.com/doc/current/performance.html
+realpath_cache_size = 4096K
+realpath_cache_ttl = 600
+opcache.interned_strings_buffer = 16
+opcache.max_accelerated_files = 20000
+opcache.memory_consumption = 256
+opcache.enable_file_override = 1
diff --git a/frankenphp/conf.d/app.prod.ini b/frankenphp/conf.d/app.prod.ini
new file mode 100644
index 00000000..3bcaa71e
--- /dev/null
+++ b/frankenphp/conf.d/app.prod.ini
@@ -0,0 +1,2 @@
+opcache.preload_user = root
+opcache.preload = /app/config/preload.php
diff --git a/frankenphp/docker-entrypoint.sh b/frankenphp/docker-entrypoint.sh
new file mode 100644
index 00000000..bdddc3ac
--- /dev/null
+++ b/frankenphp/docker-entrypoint.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then
+ # Install the project the first time PHP is started
+ # After the installation, the following block can be deleted
+ if [ ! -f composer.json ]; then
+ rm -Rf tmp/
+ composer create-project "symfony/skeleton $SYMFONY_VERSION" tmp --stability="$STABILITY" --prefer-dist --no-progress --no-interaction --no-install
+
+ cd tmp
+ cp -Rp . ..
+ cd -
+ rm -Rf tmp/
+
+ composer require "php:>=$PHP_VERSION" runtime/frankenphp-symfony
+ composer config --json extra.symfony.docker 'true'
+
+ if grep -q ^DATABASE_URL= .env; then
+ echo "To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build -d --wait"
+ sleep infinity
+ fi
+ fi
+
+ if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then
+ composer install --prefer-dist --no-progress --no-interaction
+ fi
+
+ if grep -q ^DATABASE_URL= .env; then
+ echo "Waiting for database to be ready..."
+ ATTEMPTS_LEFT_TO_REACH_DATABASE=60
+ until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do
+ if [ $? -eq 255 ]; then
+ # If the Doctrine command exits with 255, an unrecoverable error occurred
+ ATTEMPTS_LEFT_TO_REACH_DATABASE=0
+ break
+ fi
+ sleep 1
+ ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1))
+ echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left."
+ done
+
+ if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then
+ echo "The database is not up or not reachable:"
+ echo "$DATABASE_ERROR"
+ exit 1
+ else
+ echo "The database is now ready and reachable"
+ fi
+
+ if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then
+ php bin/console doctrine:migrations:migrate --no-interaction
+ fi
+ fi
+
+ setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var
+ setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var
+fi
+
+exec docker-php-entrypoint "$@"
diff --git a/frankenphp/worker.Caddyfile b/frankenphp/worker.Caddyfile
new file mode 100644
index 00000000..d384ae4c
--- /dev/null
+++ b/frankenphp/worker.Caddyfile
@@ -0,0 +1,4 @@
+worker {
+ file ./public/index.php
+ env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
+}