239 lines
7.5 KiB
Bash
Executable File
239 lines
7.5 KiB
Bash
Executable File
#!/bin/bash
|
|
set -Eeuo pipefail
|
|
|
|
echo "========================================="
|
|
echo " TerManager2 - Entrypoint"
|
|
echo "========================================="
|
|
|
|
warn() {
|
|
echo "[!] $*"
|
|
}
|
|
|
|
retry() {
|
|
local attempts="$1"
|
|
local delay="$2"
|
|
shift 2
|
|
|
|
local n=1
|
|
until "$@"; do
|
|
if [ "$n" -ge "$attempts" ]; then
|
|
return 1
|
|
fi
|
|
warn "Command failed (attempt ${n}/${attempts}). Retrying in ${delay}s..."
|
|
sleep "$delay"
|
|
n=$((n + 1))
|
|
done
|
|
}
|
|
|
|
upsert_env() {
|
|
local key="$1"
|
|
local value="$2"
|
|
local env_file="$3"
|
|
|
|
if grep -q "^${key}=" "$env_file"; then
|
|
sed -i "s|^${key}=.*|${key}=${value}|" "$env_file"
|
|
else
|
|
echo "${key}=${value}" >> "$env_file"
|
|
fi
|
|
}
|
|
|
|
read_env_value() {
|
|
local key="$1"
|
|
local env_file="$2"
|
|
|
|
if [ ! -f "$env_file" ]; then
|
|
return 0
|
|
fi
|
|
|
|
local line
|
|
line=$(grep -E "^${key}=" "$env_file" | tail -n 1 || true)
|
|
|
|
if [ -z "$line" ]; then
|
|
return 0
|
|
fi
|
|
|
|
local value="${line#*=}"
|
|
value="${value%\"}"
|
|
value="${value#\"}"
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
# -----------------------------------------------
|
|
# 0. Application code is bind-mounted from host
|
|
# -----------------------------------------------
|
|
echo "[✓] Using bind-mounted application code from host."
|
|
|
|
# -----------------------------------------------
|
|
# 0b. Create required directories & fix permissions
|
|
# -----------------------------------------------
|
|
mkdir -p storage/framework/{cache,sessions,views}
|
|
mkdir -p storage/logs
|
|
mkdir -p storage/app
|
|
mkdir -p bootstrap/cache
|
|
chown -R www-data:www-data storage bootstrap/cache
|
|
|
|
# -----------------------------------------------
|
|
# 1. .env file (must exist before composer/artisan)
|
|
# -----------------------------------------------
|
|
if [ ! -f .env ]; then
|
|
echo "[*] Creating .env from .env.example..."
|
|
cp .env.example .env
|
|
fi
|
|
|
|
# Override .env values with Docker environment variables (if set)
|
|
# This ensures Dokploy env vars take precedence
|
|
if [ -n "${APP_KEY:-}" ]; then
|
|
upsert_env "APP_KEY" "${APP_KEY}" .env
|
|
fi
|
|
if [ -n "${APP_URL:-}" ]; then
|
|
upsert_env "APP_URL" "${APP_URL}" .env
|
|
fi
|
|
if [ -n "${DB_HOST:-}" ]; then
|
|
upsert_env "DB_HOST" "${DB_HOST}" .env
|
|
fi
|
|
if [ -n "${DB_DATABASE:-}" ]; then
|
|
upsert_env "DB_DATABASE" "${DB_DATABASE}" .env
|
|
fi
|
|
if [ -n "${DB_USERNAME:-}" ]; then
|
|
upsert_env "DB_USERNAME" "${DB_USERNAME}" .env
|
|
fi
|
|
if [ -n "${DB_PASSWORD:-}" ]; then
|
|
upsert_env "DB_PASSWORD" "${DB_PASSWORD}" .env
|
|
fi
|
|
if [ -n "${REDIS_HOST:-}" ]; then
|
|
upsert_env "REDIS_HOST" "${REDIS_HOST}" .env
|
|
fi
|
|
if [ -n "${REDIS_PASSWORD:-}" ]; then
|
|
upsert_env "REDIS_PASSWORD" "${REDIS_PASSWORD}" .env
|
|
fi
|
|
echo "[✓] .env file ready."
|
|
|
|
# -----------------------------------------------
|
|
# 2. Composer install (must run before artisan commands)
|
|
# -----------------------------------------------
|
|
if [ ! -f vendor/autoload.php ]; then
|
|
echo "[*] Installing Composer dependencies..."
|
|
retry 3 5 composer install --no-interaction --prefer-dist --optimize-autoloader --no-progress
|
|
else
|
|
echo "[✓] Composer dependencies already installed."
|
|
fi
|
|
|
|
# -----------------------------------------------
|
|
# 3. Application key (persisted in storage volume)
|
|
# -----------------------------------------------
|
|
KEY_FILE="/var/www/html/storage/app/.app_key"
|
|
|
|
if [ -f "$KEY_FILE" ]; then
|
|
# Restore key from persistent volume
|
|
STORED_KEY=$(cat "$KEY_FILE")
|
|
upsert_env "APP_KEY" "$STORED_KEY" .env
|
|
echo "[✓] Application key restored from storage."
|
|
elif grep -q "^APP_KEY=$" .env; then
|
|
# No stored key and .env has empty key: generate new one
|
|
echo "[*] Generating application key..."
|
|
php artisan key:generate --ansi
|
|
# Save to persistent volume
|
|
grep '^APP_KEY=' .env | cut -d= -f2- > "$KEY_FILE"
|
|
echo "[✓] Application key saved to persistent storage."
|
|
else
|
|
# .env already has a key (from env var override or .env.example), persist it
|
|
grep '^APP_KEY=' .env | cut -d= -f2- > "$KEY_FILE"
|
|
echo "[✓] Application key already set, saved to persistent storage."
|
|
fi
|
|
|
|
# -----------------------------------------------
|
|
# 4. NPM install & build assets
|
|
# -----------------------------------------------
|
|
if [ ! -d node_modules ]; then
|
|
echo "[*] Installing NPM dependencies..."
|
|
if [ -f package-lock.json ]; then
|
|
retry 3 5 npm ci --no-audit --no-fund
|
|
else
|
|
retry 3 5 npm install --no-audit --no-fund
|
|
fi
|
|
else
|
|
echo "[✓] NPM dependencies already installed."
|
|
fi
|
|
|
|
if [ ! -f public/build/manifest.json ]; then
|
|
echo "[*] Building frontend assets..."
|
|
npm run build
|
|
else
|
|
echo "[✓] Frontend assets already built."
|
|
fi
|
|
|
|
# -----------------------------------------------
|
|
# 5. Storage link
|
|
# -----------------------------------------------
|
|
if [ ! -L public/storage ]; then
|
|
echo "[*] Creating storage symlink..."
|
|
php artisan storage:link
|
|
else
|
|
echo "[✓] Storage symlink already exists."
|
|
fi
|
|
|
|
# -----------------------------------------------
|
|
# 7. Run migrations
|
|
# -----------------------------------------------
|
|
echo "[*] Running database migrations..."
|
|
retry 10 3 php artisan migrate --force
|
|
|
|
# -----------------------------------------------
|
|
# 7b. Seed database on first container startup only
|
|
# -----------------------------------------------
|
|
SEED_MARKER_FILE="/var/www/html/storage/app/.db_seeded"
|
|
RUN_DB_SEED_ON_FIRST_START="${RUN_DB_SEED_ON_FIRST_START:-true}"
|
|
|
|
if [ "$RUN_DB_SEED_ON_FIRST_START" = "true" ]; then
|
|
if [ ! -f "$SEED_MARKER_FILE" ]; then
|
|
echo "[*] First startup detected. Running database seed..."
|
|
retry 5 3 php artisan db:seed --force
|
|
touch "$SEED_MARKER_FILE"
|
|
echo "[✓] Database seed completed and startup marker saved."
|
|
else
|
|
echo "[✓] Seed already executed on a previous startup."
|
|
fi
|
|
else
|
|
echo "[i] RUN_DB_SEED_ON_FIRST_START=false, skipping automatic seed."
|
|
fi
|
|
|
|
# -----------------------------------------------
|
|
# 7c. Ensure initial admin exists (first startup)
|
|
# -----------------------------------------------
|
|
ENSURE_INITIAL_ADMIN_ON_EMPTY_DB="${ENSURE_INITIAL_ADMIN_ON_EMPTY_DB:-true}"
|
|
|
|
INITIAL_ADMIN_NAME_VALUE="${INITIAL_ADMIN_NAME:-$(read_env_value INITIAL_ADMIN_NAME .env)}"
|
|
INITIAL_ADMIN_EMAIL_VALUE="${INITIAL_ADMIN_EMAIL:-$(read_env_value INITIAL_ADMIN_EMAIL .env)}"
|
|
INITIAL_ADMIN_PASSWORD_VALUE="${INITIAL_ADMIN_PASSWORD:-$(read_env_value INITIAL_ADMIN_PASSWORD .env)}"
|
|
|
|
if [ "$ENSURE_INITIAL_ADMIN_ON_EMPTY_DB" = "true" ]; then
|
|
echo "[*] Ensuring initial administrator account..."
|
|
if ! php artisan app:create-initial-admin \
|
|
--name="$INITIAL_ADMIN_NAME_VALUE" \
|
|
--email="$INITIAL_ADMIN_EMAIL_VALUE" \
|
|
--password="$INITIAL_ADMIN_PASSWORD_VALUE" \
|
|
--no-interaction; then
|
|
warn "Initial admin creation failed. Set INITIAL_ADMIN_NAME, INITIAL_ADMIN_EMAIL and INITIAL_ADMIN_PASSWORD."
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "[i] ENSURE_INITIAL_ADMIN_ON_EMPTY_DB=false, skipping initial admin creation check."
|
|
fi
|
|
|
|
# -----------------------------------------------
|
|
# 8. Cache config/routes/views
|
|
# -----------------------------------------------
|
|
echo "[*] Caching configuration..."
|
|
php artisan config:cache || warn "config:cache failed; continuing startup."
|
|
php artisan route:cache || warn "route:cache failed; continuing startup."
|
|
php artisan view:cache || warn "view:cache failed; continuing startup."
|
|
|
|
echo "========================================="
|
|
echo " TerManager2 - Ready!"
|
|
echo "========================================="
|
|
|
|
# -----------------------------------------------
|
|
# Execute CMD (default: php-fpm)
|
|
# -----------------------------------------------
|
|
exec "$@"
|