# PHP for both PHP stages, pinned: bump on purpose (8.5.12 fixes the # PHP2Shell RCEs, CVE-2026-109618 and CVE-2026-109619). ARG PHP_VERSION=8.5.12 # ── Stage 1: CSS build ──────────────────────────────────────────────────────── FROM node:22-slim AS node-build WORKDIR /build COPY package.json tailwind.config.js ./ RUN npm install --include=dev # Copy only what Tailwind needs to scan + the input CSS COPY web/modules/custom/riverside_pt/css/tailwind.css \ web/modules/custom/riverside_pt/css/tailwind.css COPY web/modules/custom/riverside_pt/templates/ \ web/modules/custom/riverside_pt/templates/ COPY web/modules/custom/riverside_pt/src/ \ web/modules/custom/riverside_pt/src/ COPY web/modules/custom/riverside_pt/js/components/ \ web/modules/custom/riverside_pt/js/components/ RUN npm run build # ── Stage 2: PHP extensions + Composer deps ─────────────────────────────────── FROM php:${PHP_VERSION}-fpm AS php-build RUN apt-get update && apt-get install -y --no-install-recommends \ libpq-dev \ libpng-dev \ libjpeg-dev \ libfreetype-dev \ libzip-dev \ git \ unzip \ curl \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j"$(nproc)" \ pdo_pgsql \ pgsql \ gd \ zip \ exif \ bcmath \ && rm -rf /var/lib/apt/lists/* RUN curl -fsSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer WORKDIR /var/www/html COPY composer.json ./ RUN composer config repositories.drupal composer https://packages.drupal.org/8 \ && composer require \ composer/installers:^2.3 \ drupal/core-recommended:^11 \ drupal/core-composer-scaffold:^11 \ "drush/drush:^13 || ^14" \ drupal/webform \ drupal/symfony_mailer \ drupal/claro_compact \ --no-update \ && composer install --no-dev --optimize-autoloader --no-interaction \ && rm -rf /root/.composer/cache # ── Stage 3: Runtime image ──────────────────────────────────────────────────── FROM php:${PHP_VERSION}-fpm # ── System packages ─────────────────────────────────────────────────────────── RUN apt-get update && apt-get install -y --no-install-recommends \ nginx \ supervisor \ postgresql-client \ libpq-dev \ libpng-dev \ libjpeg-dev \ libfreetype-dev \ libzip-dev \ locales \ curl \ gettext-base \ procps \ && rm -rf /var/lib/apt/lists/* # ── PHP extensions from build stage ────────────────────────────────────────── COPY --from=php-build /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/ COPY --from=php-build /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/ # Session upload progress off: it's where PHP2Shell (CVE-2026-109618/9) and # later bugs live, and Drupal doesn't use it. RUN echo 'session.upload_progress.enabled = 0' > /usr/local/etc/php/conf.d/zz-security.ini # ── All system config — done before the big vendor COPY so VFS snapshots are small ── RUN rm -f /etc/nginx/sites-enabled/default COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf.template COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY docker/php/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh \ && sed -i 's|;error_log = log/php-fpm.log|error_log = /var/log/php-fpm.log|' /usr/local/etc/php-fpm.conf \ && { \ echo 'clear_env = no'; \ echo 'catch_workers_output = yes'; \ echo 'php_admin_flag[log_errors] = on'; \ echo 'php_admin_value[error_log] = /var/log/php-fpm.www.log'; \ } >> /usr/local/etc/php-fpm.d/zz-env.conf ENV PATH="/var/www/html/vendor/bin:${PATH}" WORKDIR /var/www/html # ── Large data layers (VFS snapshots are expensive past this point) ─────────── # Scaffolded vendor/ + web/ from composer stage COPY --from=php-build /var/www/html/ ./ # Site-specific overlays on top of the scaffold COPY web/sites/default/settings.php web/sites/default/settings.php COPY web/sites/default/files/ web/sites/default/files/ COPY web/modules/custom/ web/modules/custom/ COPY --from=node-build /build/web/modules/custom/riverside_pt/css/app.css \ web/modules/custom/riverside_pt/css/app.css COPY config/sync/ config/sync/ # Download FullCalendar and Preact, and lock settings.php in one layer. # Preact (with its hooks and htm's html``) is htm's single-file standalone # build, served from the site: the components used to import Preact, its # hooks and htm/preact from esm.sh separately, and when htm/preact started # resolving to Preact 11 while the rest stayed on 10, every component # rendered nothing. Pinned by version and checksum. ARG FULLCALENDAR_VERSION=6.1.15 ARG HTM_VERSION=3.1.1 ARG HTM_PREACT_STANDALONE_SHA256=72284e8e9079c87817145df1110f74e8a2aa040b2fc384922e18dfcb46fc1fd7 RUN curl -fsSL "https://cdn.jsdelivr.net/npm/fullcalendar@${FULLCALENDAR_VERSION}/index.global.min.js" \ -o web/modules/custom/riverside_pt/js/fullcalendar.min.js \ && mkdir -p web/modules/custom/riverside_pt/js/vendor \ && curl -fsSL "https://cdn.jsdelivr.net/npm/htm@${HTM_VERSION}/preact/standalone.module.js" \ -o web/modules/custom/riverside_pt/js/vendor/preact-standalone.js \ && echo "${HTM_PREACT_STANDALONE_SHA256} web/modules/custom/riverside_pt/js/vendor/preact-standalone.js" | sha256sum -c - \ && chmod 444 web/sites/default/settings.php EXPOSE 80 ENTRYPOINT ["/entrypoint.sh"]