Files
cloud-apache-container/Dockerfile.litespeed
shadowdaoandClaude Opus 5.5 71ca114529 feat(images): upgrade lsphp from the LiteSpeed repo at build time; label PHP version
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>
2026-10-21 06:07:48 -07:00

121 lines
6.1 KiB
Docker

## cac-litespeed — OpenLiteSpeed customer container, LSAPI-native.
##
## Built on top of the LiteSpeed-maintained prebuilt image rather than
## installed-from-RPM on AlmaLinux 10. Rationale:
## - The EL10 RPM ships an empty /usr/local/lsws/cgid/ directory (the
## lscgid suexec helper is built by the upstream tarball install.sh,
## not packaged), which makes LSAPI unusable.
## - The prebuilt image is Ubuntu 24.04-based and includes lsphp +
## everything WP/WooCommerce needs out of the box (memcached, redis,
## imagick, mbstring, mysqlnd, intl, gd, soap, bcmath, gmp, sodium,
## opcache, ...) — saves us a dozen explicit installs and avoids the
## libonig.so.105 packaging bug entirely.
## - LiteSpeed Inc maintains it; OLS upgrades become a base-image bump.
##
## Tradeoff vs the rest of the CAC family: this image is Ubuntu-based,
## not AlmaLinux. The "cac" naming is now slightly misleading (it's no
## longer Cloud *Apache* Container, it's Cloud LiteSpeed Container) but
## the panel doesn't care and the customer-facing contract is identical.
## ARG before FROM is special — it can be used in the FROM line, but the
## value goes out of scope inside the image, so we re-declare ARG PHPVER
## after FROM for any RUN steps that need it.
ARG OLS_VERSION=1.8.5
ARG PHPVER=83
FROM litespeedtech/openlitespeed:${OLS_VERSION}-lsphp${PHPVER}
ARG PHPVER=83
ENV PHPVER=${PHPVER}
## Tooling we layer on top of the base:
## - gettext-base: envsubst for runtime template rendering
## - sudo: install-lscache-wp.sh runs wp-cli as the customer user
## - composer: not in the base image (wp-cli is)
## - cron: customer crontab support (mirror cac:phpXX behaviour)
## - lsphp83-ldap: not in base image, useful for some WP plugins
##
## NOTE: mariadb-server + memcached were previously installed here for
## DEV-mode parity but bloated the PROD image by ~500MB. They are now
## installed at runtime by entrypoint-litespeed.sh ONLY when
## environment=DEV, mirroring the cac:phpNN pattern. The mysql CLI
## client (used by the DEV creds-bootstrap and by wp-cli) is already
## present in the litespeedtech/openlitespeed base via the mysql-client
## package, so no client-side install is needed at build time.
##
## All apt cache is cleaned in the same layer to keep image size down.
## lsphp${PHPVER}-ldap is the only extra ext we add (everything else WP needs
## ships in the prebuilt base). lsphp84 + lsphp85 don't ship imap or pspell
## from LiteSpeed — customers needing imap should pin to 8.3 or earlier.
##
## SECURITY UPDATES AT BUILD TIME: lsphp-apt-upgrade.sh also upgrades the OS and
## sweeps EVERY installed lsphp${PHPVER}* package to the LiteSpeed repo's current
## release, failing the build if the repo is unreachable — so a rebuild ships a
## PHP security fix as soon as LiteSpeed publishes the .deb, without waiting for
## a new litespeedtech/openlitespeed base tag. See the script header.
##
## CACHE_BUST: CI passes a per-run value so this layer can never be a cache hit
## (an ARG's first use in a RUN is part of that layer's cache key). Local builds:
## pass --build-arg CACHE_BUST=$(date +%s) or use --no-cache, or you may get the
## lsphp from your last build. EXPECT_* are resolved by CI from the repo index
## and asserted here; the same values become the image labels below.
ARG CACHE_BUST=
ARG EXPECT_LSPHP_PKG=
ARG EXPECT_PHP_VERSION=
COPY ./scripts/lsphp-apt-upgrade.sh /usr/local/sbin/lsphp-apt-upgrade.sh
RUN /usr/local/sbin/lsphp-apt-upgrade.sh "${PHPVER}" \
gettext-base sudo cron \
ca-certificates curl wget \
lsphp${PHPVER}-ldap && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
## Composer (matches the wp-cli pattern in the existing CAC Dockerfile —
## phar download, no `php install` pipe since lsphp's CLI mode is fine).
RUN curl -fsSL -o /usr/local/bin/composer https://getcomposer.org/download/latest-stable/composer.phar && \
chmod +x /usr/local/bin/composer
## Our scripts + config templates layer in last (they change most often,
## keep them off the slow apt layer).
COPY ./scripts/entrypoint-litespeed.sh \
./scripts/create-vhost-litespeed.sh \
./scripts/detect-memory-litespeed.sh \
./scripts/install-lscache-wp.sh \
./scripts/log-rotate.sh \
/scripts/
RUN chmod +x /scripts/*
COPY ./configs/litespeed/ /etc/lsws-templates/
## Apply our production lsphp ini overrides. Ask lsphp for its scan dir
## directly (varies by PHP minor version: 8.3/8.4/8.5 each have their own
## /usr/local/lsws/lsphpNN/etc/php/8.M/mods-available/). Dockerfile RUN uses
## /bin/sh so we explicitly `bash -c` for safer scripting.
RUN bash -c 'set -e; \
SCAN_DIR=$(/usr/local/lsws/lsphp${PHPVER}/bin/lsphp -i 2>/dev/null | awk -F"=> " "/^Scan this dir/ {print \$2; exit}"); \
mkdir -p "$SCAN_DIR"; \
cp /etc/lsws-templates/lsphp-overrides.ini "$SCAN_DIR/99-prod-overrides.ini"; \
echo "wrote overrides to $SCAN_DIR"'
## Disable the OLS WebAdmin port for customer-facing containers. Bind admin
## listener to loopback so it's unreachable even from the docker network.
RUN sed -i 's|^[[:space:]]*address[[:space:]]\+\*:| address 127.0.0.1:|' \
/usr/local/lsws/admin/conf/admin_config.conf 2>/dev/null || true
## Cron entry for log rotation (mirrors cac:phpXX).
RUN echo "15 */12 * * * root /scripts/log-rotate.sh" >> /etc/crontab
## Inspect without running the image:
## docker buildx imagetools inspect <ref> --format '{{json .Image.Config.Labels}}'
## Values come from CI's repo-index lookup and were asserted against the
## installed packages by lsphp-apt-upgrade.sh above ("unverified" = local build).
LABEL org.whp.php-version="${EXPECT_PHP_VERSION:-unverified}" \
org.whp.lsphp-package-version="${EXPECT_LSPHP_PKG:-unverified}" \
org.whp.php-flavour="lsphp${PHPVER}"
EXPOSE 80 443
## Healthcheck: the entrypoint drops a static /healthz into the customer
## docroot at boot, so this passes even before any customer files exist.
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsSk https://127.0.0.1/healthz || exit 1
ENTRYPOINT ["/scripts/entrypoint-litespeed.sh"]