2026-11-02 05:34:02 -09:00
|
|
|
# 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
|
|
|
|
|
|
2026-06-11 22:56:14 -08:00
|
|
|
# ── 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
|
2026-04-19 20:33:56 -08:00
|
|
|
|
2026-06-11 22:56:14 -08:00
|
|
|
# ── Stage 2: PHP extensions + Composer deps ───────────────────────────────────
|
2026-11-02 05:34:02 -09:00
|
|
|
FROM php:${PHP_VERSION}-fpm AS php-build
|
2026-04-19 20:33:56 -08:00
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
|
libpq-dev \
|
|
|
|
|
libpng-dev \
|
|
|
|
|
libjpeg-dev \
|
|
|
|
|
libfreetype-dev \
|
|
|
|
|
libzip-dev \
|
|
|
|
|
git \
|
|
|
|
|
unzip \
|
2026-05-16 10:45:33 -08:00
|
|
|
curl \
|
2026-06-11 22:56:14 -08:00
|
|
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
|
|
|
|
&& docker-php-ext-install -j"$(nproc)" \
|
2026-04-19 20:33:56 -08:00
|
|
|
pdo_pgsql \
|
|
|
|
|
pgsql \
|
|
|
|
|
gd \
|
|
|
|
|
zip \
|
|
|
|
|
exif \
|
2026-06-11 22:56:14 -08:00
|
|
|
bcmath \
|
|
|
|
|
&& rm -rf /var/lib/apt/lists/*
|
2026-04-19 20:33:56 -08:00
|
|
|
|
2026-06-11 22:10:17 -08:00
|
|
|
RUN curl -fsSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
2026-04-19 20:33:56 -08:00
|
|
|
|
|
|
|
|
WORKDIR /var/www/html
|
2026-06-11 22:56:14 -08:00
|
|
|
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 ────────────────────────────────────────────────────
|
2026-11-02 05:34:02 -09:00
|
|
|
FROM php:${PHP_VERSION}-fpm
|
2026-04-19 20:33:56 -08:00
|
|
|
|
2026-06-12 00:55:53 -08:00
|
|
|
# ── System packages ───────────────────────────────────────────────────────────
|
2026-06-11 22:56:14 -08:00
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
|
nginx \
|
|
|
|
|
supervisor \
|
|
|
|
|
postgresql-client \
|
2026-06-12 00:38:31 -08:00
|
|
|
libpq-dev \
|
|
|
|
|
libpng-dev \
|
|
|
|
|
libjpeg-dev \
|
|
|
|
|
libfreetype-dev \
|
|
|
|
|
libzip-dev \
|
2026-06-11 22:56:14 -08:00
|
|
|
locales \
|
|
|
|
|
curl \
|
|
|
|
|
gettext-base \
|
|
|
|
|
procps \
|
|
|
|
|
&& rm -rf /var/lib/apt/lists/*
|
2026-05-01 03:26:46 -08:00
|
|
|
|
2026-06-12 00:55:53 -08:00
|
|
|
# ── PHP extensions from build stage ──────────────────────────────────────────
|
2026-06-11 22:56:14 -08:00
|
|
|
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/
|
2026-11-02 05:34:02 -09:00
|
|
|
# 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
|
2026-05-01 03:26:46 -08:00
|
|
|
|
2026-06-12 00:55:53 -08:00
|
|
|
# ── 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
|
2026-05-01 03:26:46 -08:00
|
|
|
|
2026-06-12 00:55:53 -08:00
|
|
|
ENV PATH="/var/www/html/vendor/bin:${PATH}"
|
2026-06-11 22:56:14 -08:00
|
|
|
WORKDIR /var/www/html
|
2026-05-01 03:26:46 -08:00
|
|
|
|
2026-06-12 00:55:53 -08:00
|
|
|
# ── Large data layers (VFS snapshots are expensive past this point) ───────────
|
|
|
|
|
|
|
|
|
|
# Scaffolded vendor/ + web/ from composer stage
|
2026-06-11 22:56:14 -08:00
|
|
|
COPY --from=php-build /var/www/html/ ./
|
2026-04-19 20:33:56 -08:00
|
|
|
|
2026-06-12 00:55:53 -08:00
|
|
|
# Site-specific overlays on top of the scaffold
|
2026-04-19 20:33:56 -08:00
|
|
|
COPY web/sites/default/settings.php web/sites/default/settings.php
|
|
|
|
|
COPY web/sites/default/files/ web/sites/default/files/
|
2026-05-01 04:39:57 -08:00
|
|
|
COPY web/modules/custom/ web/modules/custom/
|
2026-06-11 22:56:14 -08:00
|
|
|
COPY --from=node-build /build/web/modules/custom/riverside_pt/css/app.css \
|
|
|
|
|
web/modules/custom/riverside_pt/css/app.css
|
2026-06-12 00:55:53 -08:00
|
|
|
COPY config/sync/ config/sync/
|
2026-05-16 10:45:33 -08:00
|
|
|
|
Serve Preact from the site: the components rendered nothing
Every component imported Preact, its hooks and htm/preact from esm.sh
separately. htm/preact imports Preact unversioned, which esm.sh now
resolves to Preact 11, while the components asked for preact@10: two
Preacts on one page, so render() drew nothing, silently. Booking, FAQ,
testimonials, carousel, toggle and appointment type were all blank.
Use htm's single-file standalone build instead (Preact 10, its hooks and
html in one module, no further imports), downloaded at image build
pinned by version and checksum, like FullCalendar, and imported from
../vendor/preact-standalone.js. Checked on the live page: the booking
component renders again with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 06:08:05 -09:00
|
|
|
# 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.
|
2026-05-12 16:28:47 -08:00
|
|
|
ARG FULLCALENDAR_VERSION=6.1.15
|
Serve Preact from the site: the components rendered nothing
Every component imported Preact, its hooks and htm/preact from esm.sh
separately. htm/preact imports Preact unversioned, which esm.sh now
resolves to Preact 11, while the components asked for preact@10: two
Preacts on one page, so render() drew nothing, silently. Booking, FAQ,
testimonials, carousel, toggle and appointment type were all blank.
Use htm's single-file standalone build instead (Preact 10, its hooks and
html in one module, no further imports), downloaded at image build
pinned by version and checksum, like FullCalendar, and imported from
../vendor/preact-standalone.js. Checked on the live page: the booking
component renders again with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 06:08:05 -09:00
|
|
|
ARG HTM_VERSION=3.1.1
|
|
|
|
|
ARG HTM_PREACT_STANDALONE_SHA256=72284e8e9079c87817145df1110f74e8a2aa040b2fc384922e18dfcb46fc1fd7
|
2026-05-12 16:28:47 -08:00
|
|
|
RUN curl -fsSL "https://cdn.jsdelivr.net/npm/fullcalendar@${FULLCALENDAR_VERSION}/index.global.min.js" \
|
2026-06-12 00:55:53 -08:00
|
|
|
-o web/modules/custom/riverside_pt/js/fullcalendar.min.js \
|
Serve Preact from the site: the components rendered nothing
Every component imported Preact, its hooks and htm/preact from esm.sh
separately. htm/preact imports Preact unversioned, which esm.sh now
resolves to Preact 11, while the components asked for preact@10: two
Preacts on one page, so render() drew nothing, silently. Booking, FAQ,
testimonials, carousel, toggle and appointment type were all blank.
Use htm's single-file standalone build instead (Preact 10, its hooks and
html in one module, no further imports), downloaded at image build
pinned by version and checksum, like FullCalendar, and imported from
../vendor/preact-standalone.js. Checked on the live page: the booking
component renders again with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 06:08:05 -09:00
|
|
|
&& 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 - \
|
2026-06-12 00:55:53 -08:00
|
|
|
&& chmod 444 web/sites/default/settings.php
|
2026-04-19 20:33:56 -08:00
|
|
|
|
|
|
|
|
EXPOSE 80
|
|
|
|
|
ENTRYPOINT ["/entrypoint.sh"]
|