whisper-money/docker/entrypoint.sh

116 lines
3.9 KiB
Bash

#!/bin/bash
set -e
# Boot-time artisan commands run as root; this keeps any file they create
# (including laravel.log) group-writable so the www-data fpm/queue workers
# can append to it afterwards.
umask 0002
echo "=== Whisper Money Container Startup ==="
# Ensure storage directories exist (volume may be empty on first deploy)
echo "Ensuring storage directories exist..."
mkdir -p /app/storage/app/public
mkdir -p /app/storage/framework/cache/data
mkdir -p /app/storage/framework/sessions
mkdir -p /app/storage/framework/views
mkdir -p /app/storage/logs
# Pre-create the log file group-writable so a stale root-owned file from a
# persisted volume cannot block writes from the www-data workers.
touch /app/storage/logs/laravel.log
chown -R www-data:www-data /app/storage
chmod -R 775 /app/storage
chmod 664 /app/storage/logs/laravel.log
# Auto-generate APP_KEY if not set or invalid (must start with "base64:")
if [ -z "$APP_KEY" ] || [[ ! "$APP_KEY" =~ ^base64: ]]; then
if [ -n "$APP_KEY" ]; then
echo "APP_KEY is set but invalid (must start with 'base64:')"
else
echo "No APP_KEY found"
fi
echo "Generating new APP_KEY..."
APP_KEY=$(php artisan key:generate --show)
export APP_KEY
echo ""
echo "=================================================="
echo "IMPORTANT: Save this key in your environment!"
echo "APP_KEY=$APP_KEY"
echo "=================================================="
echo ""
fi
# Wait for MySQL to be ready using PHP PDO (more reliable than artisan commands)
echo "Waiting for MySQL at ${DB_HOST:-mysql}:${DB_PORT:-3306}..."
max_attempts=30
attempt=0
wait_for_mysql() {
php -r "
\$host = getenv('DB_HOST') ?: 'mysql';
\$port = getenv('DB_PORT') ?: '3306';
\$user = getenv('DB_USERNAME') ?: 'root';
\$pass = getenv('DB_PASSWORD') ?: '';
\$db = getenv('DB_DATABASE') ?: 'whisper_money';
try {
new PDO(\"mysql:host=\$host;port=\$port;dbname=\$db\", \$user, \$pass, [
PDO::ATTR_TIMEOUT => 5,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
exit(0);
} catch (Exception \$e) {
exit(1);
}
" 2>/dev/null
}
until wait_for_mysql || [ $attempt -ge $max_attempts ]; do
attempt=$((attempt + 1))
echo "MySQL not ready (attempt $attempt/$max_attempts)..."
sleep 2
done
if [ $attempt -ge $max_attempts ]; then
echo "ERROR: Could not connect to MySQL after $max_attempts attempts"
echo "DB_HOST=${DB_HOST:-mysql}, DB_PORT=${DB_PORT:-3306}, DB_DATABASE=${DB_DATABASE:-whisper_money}"
exit 1
fi
echo "MySQL is ready!"
# Run migrations
echo "Running migrations..."
php artisan migrate --force
# Ensure Passport signing keys exist (OAuth for MCP connectors). Keys provided
# via PASSPORT_PRIVATE_KEY/PASSPORT_PUBLIC_KEY env take precedence; otherwise
# generate them into storage/ (a persisted volume) so issued tokens survive
# restarts. NOTE: for a multi-instance deployment, provide the keys via env so
# every instance validates tokens with the same key.
if [ -z "$PASSPORT_PRIVATE_KEY" ] && [ ! -f /app/storage/oauth-private.key ]; then
echo "Generating Passport keys..."
php artisan passport:keys --force
fi
# Cache configuration
echo "Caching configuration..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
# Create storage link (harmless if already exists)
echo "Creating storage link..."
php artisan storage:link 2>/dev/null || true
# Re-apply storage ownership after artisan commands (may have created root-owned files)
echo "Re-applying storage ownership..."
chown -R www-data:www-data /app/storage /app/bootstrap/cache
chmod -R 775 /app/storage /app/bootstrap/cache
chmod 664 /app/storage/logs/laravel.log
echo "=== Startup complete, launching services ==="
# Start supervisor
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf