Add cac-litespeed image family (OpenLiteSpeed, native LSAPI)
New paid-tier per-customer image built on litespeedtech/openlitespeed:1.8.4-lsphpNN.
Matrix: 8.1-8.5. Native LSAPI suexec to customer uid, server-level LSCache,
all WP/WooCommerce extensions (memcached, redis, imagick, mbstring, etc.) baked in.
Files:
- Dockerfile.litespeed (FROM prebuilt LiteSpeed base, layers wp-cli/composer/mariadb)
- configs/litespeed/{httpd_config,site-template,lsphp-overrides}.tpl
- scripts/{entrypoint,create-vhost,detect-memory}-litespeed.sh + install-lscache-wp.sh
CI: new Build-LiteSpeed-Images matrix job. OLS_VERSION pinned to 1.8.4 (only
release with prebuilt images for all 5 PHP versions on Docker Hub).
Spec: whp/docs/superpowers/specs/2026-06-01-cac-litespeed-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
128
scripts/entrypoint-litespeed.sh
Normal file
128
scripts/entrypoint-litespeed.sh
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/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"
|
||||
mkdir -p "/home/$user/logs/litespeed"
|
||||
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
|
||||
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | LSAPI_CHILDREN=${LSAPI_CHILDREN} | memSoft=${LSAPI_MEM_SOFT}M memHard=${LSAPI_MEM_HARD}M | 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
|
||||
|
||||
## ---- ownership: OLS master/workers run as nobody; lsphp suexecs to the
|
||||
## customer per request (setUIDMode 2 in httpd_config.tpl). So the customer
|
||||
## owns everything under /home/$user — clean ownership model, no nobody
|
||||
## chowning. OLS's own runtime dirs stay nobody-owned.
|
||||
chown -R nobody:nogroup /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 already in the image (apt-installed
|
||||
## in the Dockerfile). Just start them.
|
||||
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/litespeed/error.log" "/home/$user/logs/litespeed/access.log"
|
||||
tail -F /usr/local/lsws/logs/error.log \
|
||||
/usr/local/lsws/logs/access.log \
|
||||
"/home/$user/logs/litespeed/error.log" \
|
||||
"/home/$user/logs/litespeed/access.log" 2>/dev/null &
|
||||
|
||||
wait "$OLS_PID"
|
||||
Reference in New Issue
Block a user