#!/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 } sync_app_code() { local env_backup="/tmp/termanager2.env.backup" rm -f "$env_backup" if [ -f /var/www/html/.env ]; then cp /var/www/html/.env "$env_backup" fi cp -a /app-src/. /var/www/html/ if [ -f "$env_backup" ]; then mv "$env_backup" /var/www/html/.env fi } # ----------------------------------------------- # 0. Sync application code from image to volume # ----------------------------------------------- IMAGE_BUILD_FILE="/app-src/.image-build-id" VOLUME_BUILD_FILE="/var/www/html/.image-build-id" if [ ! -f /var/www/html/artisan ]; then echo "[*] Syncing application code to volume..." sync_app_code elif [ -f "$IMAGE_BUILD_FILE" ] && { [ ! -f "$VOLUME_BUILD_FILE" ] || ! cmp -s "$IMAGE_BUILD_FILE" "$VOLUME_BUILD_FILE"; }; then echo "[*] New image detected. Syncing updated application code to volume..." sync_app_code else echo "[✓] Application code already in volume." fi # ----------------------------------------------- # 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 # ----------------------------------------------- # 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 "$@"