FROM almalinux/10-base ARG PHPVER=83 # Per-CI-run value: the first RUN below (dnf update) and everything after it can # never be a layer-cache hit, so every build gets the repos' current packages. # Local builds: --build-arg CACHE_BUST=$(date +%s) or --no-cache. ARG CACHE_BUST= # php.net's current release for this branch (CI); the build fails on older PHP. ARG EXPECT_PHP_MIN= # Install repos, update, install only needed packages, clean up in one layer RUN dnf install -y \ https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm \ https://rpms.remirepo.net/enterprise/remi-release-10.rpm && \ # Use Remi's origin, not the mirrorlist: during the 2026-10-21 PHP security # release the mirrors lagged hours behind (still 8.2.34 when 8.2.35 was out), # so builds shipped unpatched PHP. HTTPS first; plain http only as a fallback # because the origin's HTTPS dropped/timed out under that day's load. A # replayed (old) http index can't ship old PHP: packages stay GPG-checked and # the EXPECT_PHP_MIN gate below fails the build on anything older than php.net. sed -i -e 's|^#baseurl=http://\(.*\)$|baseurl=https://\1 http://\1|' -e 's/^mirrorlist=/#mirrorlist=/' /etc/yum.repos.d/remi*.repo && \ printf 'retries=10\ntimeout=60\n' >> /etc/dnf/dnf.conf && \ dnf update -y && \ dnf install -y httpd mod_ssl openssl wget procps cronie iproute postgresql-devel microdnf less git \ nano rsync unzip zip mariadb bind-utils jq patch nc tree dos2unix && \ dnf clean all && \ rm -rf /var/cache/dnf /usr/share/doc /usr/share/man /usr/share/locale/* # Copy scripts into the image and set permissions COPY ./scripts/ /scripts/ RUN chmod +x /scripts/* # Install ImageMagick from EPEL with HEIC/HEIF/AVIF support RUN dnf install -y ImageMagick ImageMagick-libs ImageMagick-heic && \ dnf clean all # Generate self-signed cert, create needed dirs, install PHP, clean up RUN openssl req -newkey rsa:2048 -nodes -keyout /etc/pki/tls/private/localhost.key -x509 -days 3650 -subj "/CN=localhost" -out /etc/pki/tls/certs/localhost.crt && \ mkdir -p /run/php-fpm/ && \ /scripts/install-php$PHPVER.sh && \ # CI passes php.net's current release for the branch; never ship older PHP. if [ -n "$EXPECT_PHP_MIN" ]; then \ php -r 'exit(version_compare(PHP_VERSION, getenv("EXPECT_PHP_MIN"), ">=") ? 0 : 1);' || \ { echo "FATAL: built PHP $(php -r 'echo PHP_VERSION;') is older than php.net $EXPECT_PHP_MIN"; exit 1; }; \ else echo "WARNING: no EXPECT_PHP_MIN (local build) - PHP version not gated"; fi && \ echo "PHP version report:" && php -v && rpm -q php-cli php-common php-fpm && \ rm -rf /tmp/* # Download and install wp-cli (consider pinning version for reproducibility) RUN curl -L -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \ chmod +x /usr/local/bin/wp # Download and install Composer RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ chmod +x /usr/local/bin/composer # Copy configs and web files COPY ./configs/default-index.conf /etc/httpd/conf.d/ COPY ./configs/prod-php.ini /etc/php.ini # php2shell mitigation (CVE-2026-109618/-109619). Named zz- so it sorts after # every other scan-dir ini (incl. runtime-written 99-*) and wins. Remove once # all images ship PHP >= 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12. COPY ./configs/zz-php2shell-mitigation.ini /etc/php.d/zz-php2shell-mitigation.ini COPY ./configs/phpinfo.php /var/www/html/ COPY ./configs/mariadb.repo /etc/yum.repos.d/ COPY ./configs/index.php /var/www/html/ COPY ./configs/remote_ip.conf /etc/httpd/conf.d/ COPY ./configs/whp-security.conf /etc/httpd/conf.d/ # Set up cron job in a single layer RUN echo "15 */12 * * * root /scripts/log-rotate.sh" >> /etc/crontab HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \ CMD curl -f http://localhost/ || exit 1 ENTRYPOINT [ "/scripts/entrypoint.sh" ]