Graceful stop (cac, cac-fpm, shared-httpd, and form-sender which runs cac): entrypoint.sh, entrypoint-fpm.sh and entrypoint-shared-httpd.sh end with bash as PID 1 tailing logs. PID 1 only receives signals it has a handler for, so docker stop's SIGTERM was dropped; docker waited the full 10s and SIGKILLed apache / php-fpm mid-request (exit 137). The entrypoints now trap TERM/INT and stop each daemon they started via the new scripts/stop-services.sh: httpd graceful-stop (WINCH), php-fpm QUIT, crond TERM, each with a bounded wait and a TERM/KILL fallback, budgets summing to < 10s, then exit 0. The log tail is backgrounded + `wait`ed (and shared-httpd's 60s rescan sleep likewise) so the trap runs immediately. Log streaming to docker logs is unchanged. cac-fpm error_log: entrypoint-fpm.sh `touch`ed logs/php-fpm/error.log as root AFTER its chown -R, so on a site's first start the pool (customer uid) could not open it and PHP errors went out as FastCGI stderr to shared-httpd's log until the next restart. The file is now created and chowned to the customer right after the logs dir is made, before php-fpm starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
3.3 KiB
Bash
Executable File
101 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
export CONTAINER_ROLE="httpd_only"
|
|
|
|
if [ -z "$environment" ]; then
|
|
environment="PROD"
|
|
fi
|
|
|
|
# Generate self-signed SSL cert if not already present
|
|
if [ ! -f /etc/pki/tls/certs/localhost.crt ]; then
|
|
openssl req -newkey rsa:2048 -nodes \
|
|
-keyout /etc/pki/tls/private/localhost.key \
|
|
-x509 -days 3650 -subj "/CN=localhost" \
|
|
-out /etc/pki/tls/certs/localhost.crt
|
|
fi
|
|
|
|
# Create log directory
|
|
mkdir -p /var/log/httpd
|
|
|
|
# Remove default configs that conflict
|
|
rm -f /etc/httpd/conf.d/userdir.conf
|
|
|
|
# Configure RemoteIP for Docker network
|
|
docker_network=$(ip addr show | grep eth0 | grep inet | awk -F " " '{print $2}')
|
|
if [ -n "$docker_network" ]; then
|
|
echo "RemoteIPInternalProxy $docker_network" >> /etc/httpd/conf.d/remoteip.conf
|
|
fi
|
|
|
|
# Detect memory and calculate Apache MPM tuning
|
|
source /scripts/detect-memory.sh
|
|
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | Apache workers=${APACHE_MAX_REQUEST_WORKERS} | Role=${CONTAINER_ROLE}"
|
|
|
|
# Generate MPM tuning config
|
|
/scripts/create-apache-mpm-config.sh
|
|
|
|
# Write SSL global config (matches standalone CAC behavior)
|
|
cat <<'EOF' > /etc/httpd/conf.d/ssl-global.conf
|
|
Listen 443 https
|
|
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
|
|
SSLSessionCache shmcb:/run/httpd/sslcache(512000)
|
|
SSLSessionCacheTimeout 300
|
|
SSLCryptoDevice builtin
|
|
EOF
|
|
|
|
# Disable the default ssl.conf if present (we use per-vhost SSL)
|
|
if [ -f /etc/httpd/conf.d/ssl.conf ]; then
|
|
mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak
|
|
fi
|
|
|
|
# Ensure vhosts directory exists and is included
|
|
mkdir -p /etc/httpd/conf.d/vhosts
|
|
if ! grep -q 'IncludeOptional conf.d/vhosts/' /etc/httpd/conf/httpd.conf; then
|
|
echo 'IncludeOptional conf.d/vhosts/*.conf' >> /etc/httpd/conf/httpd.conf
|
|
fi
|
|
|
|
# Start Apache
|
|
/usr/sbin/httpd -k start
|
|
|
|
# Start cron for log rotation
|
|
/usr/sbin/crond
|
|
|
|
# Graceful shutdown. bash is PID 1 here, and PID 1 only receives signals it
|
|
# has a handler for, so without this trap `docker stop`'s SIGTERM was dropped:
|
|
# docker waited the full 10s and SIGKILLed apache mid-request (exit 137), for
|
|
# every site on the host at once. graceful-stop (WINCH) lets in-flight requests
|
|
# finish; after 7s it falls back to TERM. Timeouts sum to < 10s so this
|
|
# completes inside docker's default stop timeout.
|
|
source /scripts/stop-services.sh
|
|
TAIL_PID=""
|
|
SLEEP_PID=""
|
|
shutdown() {
|
|
trap - TERM INT
|
|
echo "entrypoint-shared-httpd: received stop signal, shutting down"
|
|
stop_service httpd /etc/httpd/run/httpd.pid WINCH 7 '^/usr/sbin/httpd'
|
|
stop_service crond /run/crond.pid TERM 1 '^/usr/sbin/crond'
|
|
[ -n "$SLEEP_PID" ] && kill "$SLEEP_PID" 2>/dev/null
|
|
[ -n "$TAIL_PID" ] && kill "$TAIL_PID" 2>/dev/null
|
|
exit 0
|
|
}
|
|
trap shutdown TERM INT
|
|
|
|
# Tail Apache logs to docker logs.
|
|
# Use a loop to pick up new log files as vhosts are added.
|
|
# tail -f only watches files that exist at start time.
|
|
touch /var/log/httpd/error_log
|
|
while true; do
|
|
LOG_FILES=$(find /var/log/httpd/ -name '*.log' -o -name '*_log' 2>/dev/null | sort)
|
|
if [ -n "$TAIL_PID" ]; then
|
|
kill "$TAIL_PID" 2>/dev/null
|
|
wait "$TAIL_PID" 2>/dev/null
|
|
fi
|
|
tail -f $LOG_FILES &
|
|
TAIL_PID=$!
|
|
# Re-check for new log files every 60 seconds. Background + `wait` (not a
|
|
# foreground sleep) so a stop signal runs the trap immediately instead of
|
|
# after up to 60s.
|
|
sleep 60 &
|
|
SLEEP_PID=$!
|
|
wait "$SLEEP_PID"
|
|
done
|