Files
cloud-apache-container/scripts/entrypoint-litespeed.sh

166 lines
6.7 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
## entrypoint-litespeed.sh — PID 1 for cac-litespeed:phpNN.
## Built on litespeedtech/openlitespeed:1.8.x-lsphp83 prebuilt base. Native
## LSAPI (no FPM proxy), one customer per container.
##
## Process supervision: starts OLS via `openlitespeed -n` (no-daemon +
## crash-guard, per OLS source: lshttpdmain.cpp). SIGTERM is forwarded.
## crond runs in the background for customer crontabs; OLS itself is the
## process we wait on (if OLS dies, the container exits and Docker
## restarts it per its restart policy).
set -euo pipefail
: "${PHPVER:=83}"
: "${environment:=PROD}"
: "${LSCACHE_AUTOINSTALL:=1}"
export CONTAINER_ROLE="litespeed_only"
export PHPVER environment LSCACHE_AUTOINSTALL
## ---- env validation ----
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
: "${domain:=localhost}"
export user domain
## ---- user + directories ----
if ! id -u "$user" >/dev/null 2>&1; then
## Ubuntu's useradd; mirror what the AL10 entrypoints do with adduser
useradd -u "$uid" -m -s /bin/bash "$user"
fi
mkdir -p "/home/$user/public_html"
## Log dirs mirror cac:phpNN exactly — apache/ for web server access+error,
## php-fpm/ for PHP errors. OLS isn't Apache and lsphp isn't php-fpm, but
## the customer-facing paths stay identical so log-gathering, analytics,
## and the customer's "where do I find my access log?" mental model all
## just work without per-image-family special cases.
mkdir -p "/home/$user/logs/apache" "/home/$user/logs/php-fpm"
mkdir -p "/home/$user/lscache"
mkdir -p /tmp/lshttpd/swap
chmod 1777 /tmp/lshttpd
## ---- memory + lsphp pool sizing ----
# shellcheck source=/dev/null
source /scripts/detect-memory-litespeed.sh
feat(litespeed): wire up dynamic LSAPI tuning + idle reduction Two correctness fixes and a tuning improvement. CORRECTNESS: 1. Strip the stock 'extProcessor lsphp' from httpd_config.conf before appending ours. Previously the stock block (hard-coded PHP_LSAPI_CHILDREN=10 regardless of container memory) always won because our APPEND fragment didn't include an extProcessor block. detect-memory-litespeed.sh was computing LSAPI_CHILDREN but never plumbing it anywhere — silent dead code. 2. Bump LSPHP_WORKER_ESTIMATE_MB from 96 → 115 per the 2026-06-02 memory-sizing finding (vantagehealth OOM-spawn loop). Each lsphp carries ~115 MB shmem-rss accounted per worker. 115 MB matches the real per-worker baseline. TUNING (idle reduction, the original ask): - LSAPI_MAX_IDLE_CHILDREN=2 (was CHILDREN/2 = 5 default) - LSAPI_MAX_IDLE=60s (was 300s default) - PHP_LSAPI_MAX_REQUESTS=500 (recycle workers, prevents bloat) - memSoftLimit=1024M / memHardLimit=1500M per worker (RLIMIT_AS; catches runaway scripts at the worker level, cgroup still backstops the container) Effective LSAPI_CHILDREN per container: 2 GiB → ~17 (was 10 — brain-jar was saturating) 1 GiB → ~8 512 MiB → ~3 (cap-marginal per the memory note; bump container if site grows) Dropped LSAPI_MEM_SOFT/HARD computation in detect-memory: AVAILABLE/CHILDREN was conflating VSZ with RSS-budget arithmetic and would have killed legitimate workers. The 1024/1500 hard-coded values in the template comfortably fit typical Divi/WooCommerce VSZ (280-365 MB). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 16:36:25 -07:00
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | LSAPI_CHILDREN=${LSAPI_CHILDREN} | PHPVER=${PHPVER}"
## ---- self-signed cert (idempotent) ----
mkdir -p /usr/local/lsws/conf/cert
if [ ! -f /usr/local/lsws/conf/cert/self.crt ]; then
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
-keyout /usr/local/lsws/conf/cert/self.key \
-out /usr/local/lsws/conf/cert/self.crt \
-subj "/CN=${domain}" 2>/dev/null
fi
## ---- render httpd_config + vhconf from templates ----
/scripts/create-vhost-litespeed.sh
## ---- point PHP error_log at the same customer-visible path that
## cac:phpNN uses for php-fpm errors. Drop-in compat: customer code that
## was tailing /home/$user/logs/php-fpm/error.log on the old image will
## see lsphp's PHP errors in the exact same file on the new image.
## Rendered as a tiny ini in lsphp's scan dir; PHP merges it after the
## production-tuning overrides at startup.
SCAN_DIR=$(/usr/local/lsws/lsphp${PHPVER}/bin/lsphp -i 2>/dev/null | awk -F'=> ' '/^Scan this dir/ {print $2; exit}')
if [ -n "$SCAN_DIR" ]; then
cat > "$SCAN_DIR/99-user-error-log.ini" <<EOF
; rendered at container start by entrypoint-litespeed.sh
error_log = /home/${user}/logs/php-fpm/error.log
log_errors = On
EOF
fi
## ---- ownership: OLS runs as $user end-to-end (server-level user set by
## create-vhost-litespeed.sh, no setUIDMode). So OLS runtime dirs need to
## be customer-owned for log writes, swap files, lsphp socket creation.
## Master still starts as root for port binding, then drops privs to $user.
chown -R "$user:$user" /usr/local/lsws/logs /usr/local/lsws/conf/cert /tmp/lshttpd 2>/dev/null || true
chown -R "$user:$user" "/home/$user"
chmod 755 "/home/$user"
## ---- drop healthz so docker HEALTHCHECK passes before customer files
## Always rewrite as customer; suexec lsphp will read it as that uid too.
sudo -u "$user" sh -c "echo ok > /home/$user/public_html/healthz"
## ---- DEV: local mariadb + memcached for parity with cac entrypoints ----
if [ "$environment" = "DEV" ]; then
echo "Starting Dev Deployment (litespeed)"
mkdir -p "/home/$user/_db_backups"
## mariadb-server + memcached are NOT baked into the image (saves ~500MB
## on PROD pulls). Install them at runtime, but only once per container —
## the command -v guard means a restart of an already-bootstrapped
## container skips the apt step and DEV boot stays ~1.5s like PROD.
## First-boot in DEV adds ~30-60s for the apt install; acceptable
## tradeoff per the design spec.
if ! command -v mysqld >/dev/null 2>&1; then
echo "DEV first boot: installing mariadb-server + memcached..."
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
mariadb-server memcached
apt-get clean
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
fi
mkdir -p /run/mysqld && chown mysql:mysql /run/mysqld
nohup mysqld --user=mysql &>/dev/null &
if [ ! -f "/home/$user/mysql_creds" ]; then
sleep 10
mysql_user=$(openssl rand -hex 7)
mysql_password=$(openssl rand -hex 12)
mysql_db="devdb_$(openssl rand -hex 3)"
mysql -e "CREATE DATABASE $mysql_db;"
mysql -e "CREATE USER '$mysql_user'@'localhost' IDENTIFIED BY '$mysql_password';"
mysql -e "GRANT ALL PRIVILEGES ON *.* TO '$mysql_user'@'localhost' WITH GRANT OPTION;"
mysql -e "FLUSH PRIVILEGES;"
{
echo "MySQL User: $mysql_user"
echo "MySQL Password: $mysql_password"
echo "MySQL Database: $mysql_db"
} > "/home/$user/mysql_creds"
cat "/home/$user/mysql_creds"
fi
/usr/bin/memcached -d -u "$user"
fi
## ---- user crontab ----
if [ ! -f "/home/$user/crontab" ]; then
{
echo "# User crontab for $user"
echo "# Add your cron jobs here"
} > "/home/$user/crontab"
chown "$user:$user" "/home/$user/crontab"
fi
crontab -u "$user" "/home/$user/crontab"
service cron start >/dev/null 2>&1 || /usr/sbin/cron
## ---- LSCache plugin (background, non-fatal) ----
( /scripts/install-lscache-wp.sh "$user" >>/var/log/lscache-install.log 2>&1 || true ) &
## ---- start OLS in foreground with crash-guard ----
## openlitespeed -n = no-daemon + supervisor. Trap forwards SIGTERM cleanly.
OLS_PID=""
trap '[ -n "$OLS_PID" ] && kill -TERM "$OLS_PID" 2>/dev/null; wait "$OLS_PID" 2>/dev/null || true' TERM INT
/usr/local/lsws/bin/openlitespeed -n &
OLS_PID=$!
## Stream OLS + customer logs to PID-1 stdout so `docker logs` works.
touch /usr/local/lsws/logs/error.log /usr/local/lsws/logs/access.log
touch "/home/$user/logs/apache/error_log" "/home/$user/logs/apache/access_log"
touch "/home/$user/logs/php-fpm/error.log"
chown "$user:$user" "/home/$user/logs/apache/error_log" \
"/home/$user/logs/apache/access_log" \
"/home/$user/logs/php-fpm/error.log"
tail -F /usr/local/lsws/logs/error.log \
/usr/local/lsws/logs/access.log \
"/home/$user/logs/apache/error_log" \
"/home/$user/logs/apache/access_log" \
"/home/$user/logs/php-fpm/error.log" 2>/dev/null &
wait "$OLS_PID"