Code-review integration fixes: - entrypoint-lsphp.sh: the shared-ols tier mounts the docroot at /mnt/users/<user>/<domain> (NOT /home/$user). Discover the mount via glob (one site per sidecar; wildcard-safe), create public_html + logs/php-fpm under it (so OLS docRoot exists), point lsphp error_log there, and chown just those dirs. Verified: sidecar creates public_html under the mount, runs as the per-site user, OLS serves PHP (SAPI=litespeed) end-to-end. - shared-ols vhconf.tpl: per-vhost logs -> /usr/local/lsws/logs/<vhname>.* (the shared-ols container has no /home/<user>). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
130 lines
6.1 KiB
Bash
130 lines
6.1 KiB
Bash
#!/usr/bin/env bash
|
|
## entrypoint-lsphp.sh — PID 1 for cac-lsphp:phpNN.
|
|
##
|
|
## The per-site PHP backend for the SHARED OpenLiteSpeed tier. Runs lsphp in
|
|
## DETACHED LSAPI mode (`lsphp -b <addr:port>`) and nothing else — no
|
|
## webserver. The shared-ols container connects to this over the docker
|
|
## network (extProcessor type lsapi, address <this-container>:9000) exactly
|
|
## like the shared httpd connects to a cac-fpm container's php-fpm on :9000.
|
|
##
|
|
## Structurally this is the LiteSpeed analogue of entrypoint-fpm.sh: same
|
|
## `uid`/`user` contract, same /home/$user/{public_html,logs} layout, same
|
|
## per-site ini drop-in mechanism as entrypoint-litespeed.sh. The only
|
|
## difference from cac-litespeed is that OLS lives elsewhere, so this PID 1 is
|
|
## lsphp itself rather than a webserver supervisor.
|
|
##
|
|
## IMPORTANT (see whp memory feedback_ols_lsapi_no_script_filename_remap):
|
|
## OLS hands lsphp exactly its vhost docRoot path, so the shared-ols vhost
|
|
## docRoot and THIS container's docroot mount MUST be the same absolute path.
|
|
## The panel mounts the site at /mnt/users/<user>/<domain> in BOTH containers;
|
|
## this entrypoint does not assume any particular path — it just runs lsphp,
|
|
## which opens whatever absolute SCRIPT_FILENAME the webserver sends.
|
|
|
|
set -euo pipefail
|
|
|
|
: "${PHPVER:=83}"
|
|
: "${environment:=PROD}"
|
|
export CONTAINER_ROLE="lsphp_only"
|
|
export PHPVER environment
|
|
|
|
## ---- env validation (same contract as entrypoint-fpm / entrypoint-litespeed) ----
|
|
if [ -z "${uid:-}" ] || [ -z "${user:-}" ]; then
|
|
echo "FATAL: 'uid' and 'user' env vars are required (panel sets these from WHP_UID/WHP_USER)." >&2
|
|
exit 1
|
|
fi
|
|
export user
|
|
|
|
LSPHP_BIN="/usr/local/lsws/lsphp${PHPVER}/bin/lsphp"
|
|
if [ ! -x "$LSPHP_BIN" ]; then
|
|
echo "FATAL: lsphp binary not found at $LSPHP_BIN (PHPVER=$PHPVER)." >&2
|
|
exit 1
|
|
fi
|
|
|
|
## ---- user ----
|
|
if ! id -u "$user" >/dev/null 2>&1; then
|
|
useradd -u "$uid" -m -s /bin/bash "$user"
|
|
fi
|
|
|
|
## ---- locate the customer docroot ----
|
|
## Unlike cac-fpm/cac-litespeed (docroot at /home/$user), the shared-ols tier
|
|
## mounts each site at /mnt/users/<user>/<domain> — the SAME absolute path the
|
|
## shared-ols vhost uses as docRoot, because OLS hands lsphp exactly that path as
|
|
## SCRIPT_FILENAME (feedback_ols_lsapi_no_script_filename_remap). The panel
|
|
## mounts exactly ONE site dir here, so glob it (wildcard-safe: the on-disk dir
|
|
## is wildcard.<domain> for wildcard sites, which the glob picks up verbatim).
|
|
SITE_DIR=""
|
|
for d in /mnt/users/"$user"/*/; do
|
|
[ -d "$d" ] || continue
|
|
SITE_DIR="${d%/}"
|
|
break
|
|
done
|
|
if [ -z "$SITE_DIR" ]; then
|
|
## No bind mount yet (e.g. hand-run for testing) — fall back to a sane path so
|
|
## lsphp still starts; OLS will send the real docRoot at request time.
|
|
SITE_DIR="/mnt/users/$user/site"
|
|
fi
|
|
mkdir -p "$SITE_DIR/public_html" "$SITE_DIR/logs/php-fpm"
|
|
|
|
## ---- detached-lsphp pool sizing ----
|
|
# shellcheck source=/dev/null
|
|
source /scripts/detect-memory-lsphp.sh
|
|
|
|
## LSAPI tuning (spec §5.1). PHP_LSAPI_CHILDREN MUST equal the shared-ols vhost
|
|
## maxConns — the WHP panel writes both from the single fpm_max_children value,
|
|
## so they can't drift. LSAPI_MAX_IDLE is THE RAM win: idle children exit, so an
|
|
## idle site's footprint collapses toward baseline (ondemand-like).
|
|
export PHP_LSAPI_CHILDREN="${PHP_LSAPI_CHILDREN:-$LSAPI_CHILDREN}"
|
|
export PHP_LSAPI_MAX_REQUESTS="${PHP_LSAPI_MAX_REQUESTS:-500}"
|
|
export LSAPI_MAX_IDLE="${LSAPI_MAX_IDLE:-30}"
|
|
export LSAPI_EXTRA_CHILDREN="${LSAPI_EXTRA_CHILDREN:-5}"
|
|
export LSAPI_AVOID_FORK="${LSAPI_AVOID_FORK:-0}"
|
|
LSPHP_BIND="${LSPHP_BIND:-0.0.0.0:9000}"
|
|
|
|
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | PHP_LSAPI_CHILDREN=${PHP_LSAPI_CHILDREN} | LSAPI_MAX_IDLE=${LSAPI_MAX_IDLE} | PHPVER=${PHPVER} | bind=${LSPHP_BIND}"
|
|
|
|
## ---- per-site ini drop-ins (identical mechanism to entrypoint-litespeed.sh) ----
|
|
## error_log → the same customer-visible path cac:phpNN / cac-litespeed use, so
|
|
## "where's my PHP error log?" is answered identically across all site types.
|
|
SCAN_DIR=$("$LSPHP_BIN" -i 2>/dev/null | awk -F'=> ' '/^Scan this dir/ {print $2; exit}')
|
|
if [ -n "$SCAN_DIR" ]; then
|
|
mkdir -p "$SCAN_DIR"
|
|
cat > "$SCAN_DIR/99-user-error-log.ini" <<EOF
|
|
; rendered at container start by entrypoint-lsphp.sh
|
|
error_log = ${SITE_DIR}/logs/php-fpm/error.log
|
|
log_errors = On
|
|
EOF
|
|
## Per-site opcache override (panel: Advanced Tuning → OpCache size); falls
|
|
## back to the baked lsphp-overrides.ini defaults when unset.
|
|
if [ -n "${OPCACHE_MEMORY_MB:-}" ] || [ -n "${OPCACHE_MAX_FILES:-}" ]; then
|
|
{
|
|
echo "; rendered at container start by entrypoint-lsphp.sh"
|
|
echo "; per-site override from WHP whp.sites.opcache_*_override"
|
|
[ -n "${OPCACHE_MEMORY_MB:-}" ] && echo "opcache.memory_consumption = ${OPCACHE_MEMORY_MB}"
|
|
[ -n "${OPCACHE_MAX_FILES:-}" ] && echo "opcache.max_accelerated_files = ${OPCACHE_MAX_FILES}"
|
|
} > "$SCAN_DIR/99-user-opcache.ini"
|
|
fi
|
|
fi
|
|
|
|
## ---- ownership ----
|
|
## Own the docroot + logs so lsphp (running as $user) can read code and write
|
|
## logs. Don't recurse the whole tree blindly — just ensure the dirs we created
|
|
## and the log file are customer-owned (customer content may be large; a full
|
|
## recursive chown every boot would be wasteful, and the files are already
|
|
## customer-owned from the host side).
|
|
touch "$SITE_DIR/logs/php-fpm/error.log"
|
|
chown "$uid:$uid" "$SITE_DIR" "$SITE_DIR/public_html" "$SITE_DIR/logs" "$SITE_DIR/logs/php-fpm" "$SITE_DIR/logs/php-fpm/error.log" 2>/dev/null || true
|
|
|
|
## ---- exec lsphp -b as the customer user (PID 1) ----
|
|
## Bind port is unprivileged (9000), so no root port-bind step is needed — start
|
|
## directly as $user. Prefer setpriv (util-linux, on the Ubuntu base); fall back
|
|
## to runuser. exec so lsphp becomes PID 1 and receives Docker's signals
|
|
## directly (clean stop/restart, matches the php-fpm container's lifecycle).
|
|
echo "entrypoint-lsphp: exec $LSPHP_BIN -b $LSPHP_BIND as $user (uid=$uid)"
|
|
if command -v setpriv >/dev/null 2>&1; then
|
|
exec setpriv --reuid "$uid" --regid "$uid" --init-groups "$LSPHP_BIN" -b "$LSPHP_BIND"
|
|
elif command -v runuser >/dev/null 2>&1; then
|
|
exec runuser -u "$user" -- "$LSPHP_BIN" -b "$LSPHP_BIND"
|
|
else
|
|
exec sudo -u "$user" -E "$LSPHP_BIN" -b "$LSPHP_BIND"
|
|
fi
|