Security review follow-up for the opt-in PKG_CACHE path:
- PKG_CACHE must be https:// (http is refused). The cache's certificate
comes from a name-constrained internal CA (keys/pkg-cache/ca.crt, valid
only for 192.168.1.40 / pkg-cache.*). The CA is trusted only by the
rewritten repos (dnf sslcacert bundle, apt per-host CaInfo) and only
for the duration of the RUN.
- epel-release / remi-release are no longer installed straight from a
URL. release-install downloads them over HTTPS, checks the package name,
imports the signing keys committed in keys/pkg-cache/ and requires
`rpm -K` "signatures OK", then installs with localpkg_gpgcheck=1. This
applies with and without the cache.
- Rewritten repos get gpgcheck=1. Remi and AlmaLinux also get
repo_gpgcheck=1, since both sign repomd.xml. EPEL does not publish a
repomd signature, so it relies on end-to-end HTTPS.
- restore also deletes files it created and any new repo/apt file that
still references the cache, then fails the build if a reference remains
under /etc/yum.repos.d, /etc/dnf or /etc/apt.
- docs: trust model, replay risk, proposed openssl/httpd/ImageMagick
minimum-version gates, TLS registry mirror (BuildKit ca= / dockerd
certs.d, no insecure-registries).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds scripts/pkg-cache-repos.sh and wires it into Dockerfile,
Dockerfile.fpm, Dockerfile.shared-httpd and Dockerfile.shared-ols. With
--build-arg PKG_CACHE=http://192.168.1.40 (CT130 pkg-cache), dnf/apt go
through the LAN cache. That cache fetches from the Remi/EPEL/AlmaLinux/
Ubuntu/LiteSpeed origins over HTTPS, with fallback tiers and
stale-on-error. Without the arg the script is a no-op and builds are
unchanged.
- rpm: each baseurl becomes "<cache>/<prefix>/... <origin>/...", so dnf
fails over to the origin if the cache dies mid-build
- every RUN restores the original repo files before it ends, so no
shipped layer carries the LAN address
- EPEL/Remi release RPMs come from the cache when it is set
- the php.net version gates are untouched
Dockerfile.litespeed/.lsphp are not wired yet (see docs/pkg-cache.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Security review of #28: plain-http repo metadata could be replayed to keep a
build on old (validly signed) vulnerable PHP. The origin is now tried over
HTTPS first, with http only as a fallback (its HTTPS timed out/reset under the
2026-10-21 release load). CI resolves php.net's current release per branch
(over HTTPS) and the build fails if the installed PHP is older, so neither a
lagging mirror nor replayed metadata can ship a vulnerable PHP.
Tested on 192.168.1.193 (almalinux/10-base): rewritten baseurl installs PHP
8.5.12; the gate passes at 8.5.12 and fails at 8.5.99.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
During the php2shell release the Remi mirrors still served 8.2.34 hours after
8.2.35 was published, so cac/cac-fpm builds shipped vulnerable PHP. Enable the
repo files' baseurl (rpms.remirepo.net) and comment the mirrorlist. Verified on
the build server: a clean almalinux/10-base install now gets PHP 8.2.35.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CVE-2026-109618 / CVE-2026-109619 (GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp).
Adds configs/zz-php2shell-mitigation.ini (fatal_error_backtraces=0,
session.upload_progress.enabled=0, max_input_nesting_level=16) and installs it
into each image's PHP scan dir as zz-php2shell-mitigation.ini so it sorts after
99-prod-overrides.ini and the entrypoint-written 99-* fragments:
- Dockerfile / Dockerfile.fpm: COPY to /etc/php.d/ next to prod-php.ini.
- Dockerfile.lsphp / Dockerfile.litespeed: COPY to /etc/lsws-templates/ and
cp into the computed lsphp $SCAN_DIR in the existing overrides RUN.
fatal_error_backtraces is unknown to (and silently ignored by) PHP < 8.5, so
one file serves every version. Remove once all images ship
PHP >= 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cac-litespeed and cac-lsphp start FROM litespeedtech/openlitespeed:1.8.4-lsphpNN,
which ships lsphp85 8.5.0 / lsphp84 8.4.15 (built 2025-12). lsphp only moved
forward as a side effect of installing lsphpNN-ldap. lsphp-apt-upgrade.sh now
sweeps every installed lsphpNN* package (and OS packages) to the repo's current
release on every build and fails the build if the repo is unreachable or the
result doesn't match what CI resolved from the repo index. CI passes a per-run
CACHE_BUST so the upgrade layer is never a cache hit, and images carry
org.whp.php-version / org.whp.lsphp-package-version labels.
Tested on .148 (2026-10-21): cac-lsphp php85/php84 and cac-litespeed php85 built
from this branch report the same PHP (8.5.11 / 8.4.26), identical module lists
and OLS 1.8.4 as the current registry images; with the hardening flags each
serves/runs PHP as the customer uid, restarts, and stops cleanly (exit 0).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on .148: standalone cac served /.env with its contents, and
cac-litespeed served /.env even at mode 0640 (OLS runs as the customer uid
there). shared-httpd and shared-ols already deny these via WHP's drop-ins; the
standalone tiers never got them.
- cac: new configs/whp-security.conf in /etc/httpd/conf.d — the same named
FilesMatch + DirectoryMatch list as WHP's shared-httpd-security.conf,
re-rooted to /home.
- cac-litespeed: the same `context exp:` regex as WHP's shared-ols vhconf
template, added to the vhost template.
Named list (.user.ini .env* .git .svn .hg .bzr .ht* .whp .site-builder), not a
blanket dotfile deny, so /.well-known/ stays reachable. HTTP only: PHP still
reads these files from disk.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Added ImageMagick-heic package to both Dockerfile and Dockerfile.fpm.
This is a separate EPEL subpackage that provides HEIC, HEIF, and AVIF
format support via libheif. Without it, ImageMagick is installed but
cannot process iPhone photos and modern image formats.
Also fixed MariaDB repo URL: AlmaLinux 10 uses $releasever=10 but
MariaDB mirrors don't have an 'almalinux10' directory. Changed to
'rhel10' which is the supported path for EL10 derivatives.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AlmaLinux 10 base image does not include openssl by default (AL9 did).
Add it explicitly to all three Dockerfiles since it's needed for
self-signed cert generation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bump all three Dockerfiles to almalinux/10-base with matching EPEL 10
and Remi 10 repository URLs. AlmaLinux 10.1 has been stable since Nov
2025. All PHP versions (7.4-8.5) confirmed available via Remi for EL10.
Also removes --allowerasing from shared-httpd Dockerfile since AL10
base does not ship curl-minimal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The official ImageMagick 7.1.2-18 RPMs require GLIBC 2.38 which is not
available on AlmaLinux 9 (ships GLIBC 2.34). Switch to EPEL-provided
ImageMagick packages which are built for EL9 and guaranteed compatible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds ImageMagick and ImageMagick-libs from the official CentOS x86_64
RPMs before PHP installation so php-pecl-imagick links against the
latest version. Applied to both Dockerfile (standalone) and
Dockerfile.fpm (shared httpd mode).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added git, nano, rsync, unzip, zip, mariadb client, bind-utils, jq, patch, nc, tree, and dos2unix to provide developers with commonly needed tools for PHP development and debugging.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Install Composer globally at /usr/local/bin/composer
- Available for all PHP versions and users
- Also includes previously added microdnf and less utilities
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added postgresql-devel package to Dockerfile for client libraries
- Added php-pgsql extension to all PHP versions (7.4, 8.0, 8.1, 8.2, 8.3, 8.4)
- Enables PHP applications to connect to PostgreSQL databases
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>