diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php index a26e7daaa..b5ebd92b2 100644 --- a/app/Actions/Server/UpdateCoolify.php +++ b/app/Actions/Server/UpdateCoolify.php @@ -30,7 +30,6 @@ public function handle($manual_update = false) if (! $this->server) { return; } - CleanupDocker::dispatch($this->server, false, false); // Fetch fresh version from CDN instead of using cache try { @@ -117,17 +116,12 @@ public function handle($manual_update = false) private function update() { - $helperImage = config('constants.coolify.helper_image'); - $latest_version = getHelperVersion(); - instant_remote_process(["docker pull -q {$helperImage}:{$latest_version}"], $this->server, false); - - $image = config('constants.coolify.registry_url').'/coollabsio/coolify:'.$this->latestVersion; - instant_remote_process(["docker pull -q $image"], $this->server, false); - + $latestHelperImageVersion = getHelperVersion(); $upgradeScriptUrl = config('constants.coolify.upgrade_script_url'); + remote_process([ "curl -fsSL {$upgradeScriptUrl} -o /data/coolify/source/upgrade.sh", - "bash /data/coolify/source/upgrade.sh $this->latestVersion", + "bash /data/coolify/source/upgrade.sh $this->latestVersion $latestHelperImageVersion", ], $this->server); } } diff --git a/app/Livewire/Upgrade.php b/app/Livewire/Upgrade.php index f13baa7a7..36bee2a23 100644 --- a/app/Livewire/Upgrade.php +++ b/app/Livewire/Upgrade.php @@ -4,6 +4,7 @@ use App\Actions\Server\UpdateCoolify; use App\Models\InstanceSettings; +use App\Models\Server; use Livewire\Component; class Upgrade extends Component @@ -14,12 +15,20 @@ class Upgrade extends Component public string $latestVersion = ''; + public string $currentVersion = ''; + protected $listeners = ['updateAvailable' => 'checkUpdate']; + public function mount() + { + $this->currentVersion = config('constants.coolify.version'); + } + public function checkUpdate() { try { $this->latestVersion = get_latest_version_of_coolify(); + $this->currentVersion = config('constants.coolify.version'); $this->isUpgradeAvailable = data_get(InstanceSettings::get(), 'new_version_available', false); if (isDev()) { $this->isUpgradeAvailable = true; @@ -41,4 +50,71 @@ public function upgrade() return handleError($e, $this); } } + + public function getUpgradeStatus(): array + { + // Only root team members can view upgrade status + if (auth()->user()?->currentTeam()?->id !== 0) { + return ['status' => 'none']; + } + + $server = Server::find(0); + if (! $server) { + return ['status' => 'none']; + } + + $statusFile = '/data/coolify/source/.upgrade-status'; + + try { + $content = instant_remote_process( + ["cat {$statusFile} 2>/dev/null || echo ''"], + $server, + false + ); + $content = trim($content ?? ''); + } catch (\Throwable $e) { + return ['status' => 'none']; + } + + if (empty($content)) { + return ['status' => 'none']; + } + + $parts = explode('|', $content); + if (count($parts) < 3) { + return ['status' => 'none']; + } + + [$step, $message, $timestamp] = $parts; + + // Check if status is stale (older than 10 minutes) + try { + $statusTime = new \DateTime($timestamp); + $now = new \DateTime; + $diffMinutes = ($now->getTimestamp() - $statusTime->getTimestamp()) / 60; + + if ($diffMinutes > 10) { + return ['status' => 'none']; + } + } catch (\Throwable $e) { + return ['status' => 'none']; + } + + if ($step === 'error') { + return [ + 'status' => 'error', + 'step' => 0, + 'message' => $message, + ]; + } + + $stepInt = (int) $step; + $status = $stepInt >= 6 ? 'complete' : 'in_progress'; + + return [ + 'status' => $status, + 'step' => $stepInt, + 'message' => $message, + ]; + } } diff --git a/other/nightly/upgrade.sh b/other/nightly/upgrade.sh index bfcd11095..0d3896647 100644 --- a/other/nightly/upgrade.sh +++ b/other/nightly/upgrade.sh @@ -64,9 +64,45 @@ if [ -f /root/.docker/config.json ]; then DOCKER_CONFIG_MOUNT="-v /root/.docker/config.json:/root/.docker/config.json" fi -if [ -f /data/coolify/source/docker-compose.custom.yml ]; then - echo "docker-compose.custom.yml detected." >>"$LOGFILE" - docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock ${DOCKER_CONFIG_MOUNT} --rm ${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:${LATEST_HELPER_VERSION} bash -c "LATEST_IMAGE=${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --wait --wait-timeout 60" >>"$LOGFILE" 2>&1 -else - docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock ${DOCKER_CONFIG_MOUNT} --rm ${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:${LATEST_HELPER_VERSION} bash -c "LATEST_IMAGE=${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --remove-orphans --wait --wait-timeout 60" >>"$LOGFILE" 2>&1 -fi +# Pull all required images before stopping containers +# This ensures we don't take down the system if image pull fails (rate limits, network issues, etc.) +echo "Pulling required Docker images..." >>"$LOGFILE" +docker pull "${REGISTRY_URL:-ghcr.io}/coollabsio/coolify:${LATEST_IMAGE}" >>"$LOGFILE" 2>&1 || { echo "Failed to pull Coolify image. Aborting upgrade." >>"$LOGFILE"; exit 1; } +docker pull "${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:${LATEST_HELPER_VERSION}" >>"$LOGFILE" 2>&1 || { echo "Failed to pull Coolify helper image. Aborting upgrade." >>"$LOGFILE"; exit 1; } +docker pull postgres:15-alpine >>"$LOGFILE" 2>&1 || { echo "Failed to pull PostgreSQL image. Aborting upgrade." >>"$LOGFILE"; exit 1; } +docker pull redis:7-alpine >>"$LOGFILE" 2>&1 || { echo "Failed to pull Redis image. Aborting upgrade." >>"$LOGFILE"; exit 1; } +# Pull realtime image - version is hardcoded in docker-compose.prod.yml, extract it or use a known version +docker pull "${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.10" >>"$LOGFILE" 2>&1 || { echo "Failed to pull Coolify realtime image. Aborting upgrade." >>"$LOGFILE"; exit 1; } +echo "All images pulled successfully." >>"$LOGFILE" + +# Stop and remove existing Coolify containers to prevent conflicts +# This handles both old installations (project "source") and new ones (project "coolify") +# Use nohup to ensure the script continues even if SSH connection is lost +echo "Starting container restart sequence (detached)..." >>"$LOGFILE" + +nohup bash -c " + LOGFILE='$LOGFILE' + DOCKER_CONFIG_MOUNT='$DOCKER_CONFIG_MOUNT' + REGISTRY_URL='$REGISTRY_URL' + LATEST_HELPER_VERSION='$LATEST_HELPER_VERSION' + LATEST_IMAGE='$LATEST_IMAGE' + + # Stop and remove containers + echo 'Stopping existing Coolify containers...' >>\"\$LOGFILE\" + for container in coolify coolify-db coolify-redis coolify-realtime; do + if docker ps -a --format '{{.Names}}' | grep -q \"^\${container}\$\"; then + docker stop \"\$container\" >>\"\$LOGFILE\" 2>&1 || true + docker rm \"\$container\" >>\"\$LOGFILE\" 2>&1 || true + echo \" - Removed container: \$container\" >>\"\$LOGFILE\" + fi + done + + # Start new containers + if [ -f /data/coolify/source/docker-compose.custom.yml ]; then + echo 'docker-compose.custom.yml detected.' >>\"\$LOGFILE\" + docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock \${DOCKER_CONFIG_MOUNT} --rm \${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:\${LATEST_HELPER_VERSION} bash -c \"LATEST_IMAGE=\${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --wait --wait-timeout 60\" >>\"\$LOGFILE\" 2>&1 + else + docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock \${DOCKER_CONFIG_MOUNT} --rm \${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:\${LATEST_HELPER_VERSION} bash -c \"LATEST_IMAGE=\${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --remove-orphans --wait --wait-timeout 60\" >>\"\$LOGFILE\" 2>&1 + fi + echo 'Upgrade completed.' >>\"\$LOGFILE\" +" >>"$LOGFILE" 2>&1 & diff --git a/resources/views/components/upgrade-progress.blade.php b/resources/views/components/upgrade-progress.blade.php new file mode 100644 index 000000000..d65273cce --- /dev/null +++ b/resources/views/components/upgrade-progress.blade.php @@ -0,0 +1,152 @@ +@props(['step' => 0]) + +{{-- + Step Mapping (Backend → UI): + Backend steps 1-2 (config download, env update) → UI Step 1: Preparing + Backend step 3 (pulling images) → UI Step 2: Helper + UI Step 3: Image + Backend steps 4-5 (stop/start containers) → UI Step 4: Restart + Backend step 6 (complete) → mapped in JS mapStepToUI() in upgrade.blade.php + + The currentStep variable is inherited from parent Alpine component (upgradeModal). +--}} +
+
+ {{-- Step 1: Preparing --}} +
+
+
+ + + +
+ Preparing +
+
+
+ + {{-- Step 2: Helper --}} +
+
+
+ + + +
+ Helper +
+
+
+ + {{-- Step 3: Image --}} +
+
+
+ + + +
+ Image +
+
+
+ + {{-- Step 4: Restart --}} +
+
+
+ + + +
+ Restart +
+
+
+
diff --git a/resources/views/livewire/upgrade.blade.php b/resources/views/livewire/upgrade.blade.php index 37e43935d..dcc664e84 100644 --- a/resources/views/livewire/upgrade.blade.php +++ b/resources/views/livewire/upgrade.blade.php @@ -1,21 +1,22 @@
+ x-init="$wire.checkUpdate" x-data="upgradeModal({ + currentVersion: @js($currentVersion), + latestVersion: @js($latestVersion) + })"> @if ($isUpgradeAvailable)
-
-

Are you sure you would like to upgrade your instance to {{ $latestVersion }}?

-
- -

Any deployments running during the update process will - fail. Please ensure no deployments are in progress on any server before continuing. -

-
-
-

You can review the changelogs here.

-
-

If something goes wrong and you cannot upgrade your instance, You can check the following - guide on what to do. -

-
-

Progress

-
-
+ {{-- Content --}} +
+ {{-- Progress View --}} + + + {{-- Confirmation View --}} +
+ + {{-- Footer Actions --}}
Cancel
- Continue + + Upgrade Now
@@ -89,23 +176,64 @@ class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300">Cancel + \ No newline at end of file diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh index f091d2fdb..4259aded2 100644 --- a/scripts/upgrade.sh +++ b/scripts/upgrade.sh @@ -7,27 +7,101 @@ LATEST_HELPER_VERSION=${2:-latest} REGISTRY_URL=${3:-ghcr.io} SKIP_BACKUP=${4:-false} ENV_FILE="/data/coolify/source/.env" +STATUS_FILE="/data/coolify/source/.upgrade-status" DATE=$(date +%Y-%m-%d-%H-%M-%S) LOGFILE="/data/coolify/source/upgrade-${DATE}.log" +# Helper function to log with timestamp +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >>"$LOGFILE" +} + +# Helper function to log section headers +log_section() { + echo "" >>"$LOGFILE" + echo "============================================================" >>"$LOGFILE" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >>"$LOGFILE" + echo "============================================================" >>"$LOGFILE" +} + +# Helper function to write upgrade status for API polling +write_status() { + local step="$1" + local message="$2" + echo "${step}|${message}|$(date -Iseconds)" > "$STATUS_FILE" +} + +echo "" +echo "==========================================" +echo " Coolify Upgrade - ${DATE}" +echo "==========================================" +echo "" + +# Initialize log file with header +echo "============================================================" >>"$LOGFILE" +echo "Coolify Upgrade Log" >>"$LOGFILE" +echo "Started: $(date '+%Y-%m-%d %H:%M:%S')" >>"$LOGFILE" +echo "Target Version: ${LATEST_IMAGE}" >>"$LOGFILE" +echo "Helper Version: ${LATEST_HELPER_VERSION}" >>"$LOGFILE" +echo "Registry URL: ${REGISTRY_URL}" >>"$LOGFILE" +echo "============================================================" >>"$LOGFILE" + +log_section "Step 1/6: Downloading configuration files" +write_status "1" "Downloading configuration files" +echo "1/6 Downloading latest configuration files..." +log "Downloading docker-compose.yml from ${CDN}/docker-compose.yml" curl -fsSL -L $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml +log "Downloading docker-compose.prod.yml from ${CDN}/docker-compose.prod.yml" curl -fsSL -L $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml +log "Downloading .env.production from ${CDN}/.env.production" curl -fsSL -L $CDN/.env.production -o /data/coolify/source/.env.production +log "Configuration files downloaded successfully" +echo " Done." + +# Extract all images from docker-compose configuration +log "Extracting all images from docker-compose configuration..." +COMPOSE_FILES="-f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml" + +# Check if custom compose file exists +if [ -f /data/coolify/source/docker-compose.custom.yml ]; then + COMPOSE_FILES="$COMPOSE_FILES -f /data/coolify/source/docker-compose.custom.yml" + log "Including custom docker-compose.yml in image extraction" +fi + +# Get all unique images from docker compose config +# LATEST_IMAGE env var is needed for image substitution in compose files +IMAGES=$(LATEST_IMAGE=${LATEST_IMAGE} docker compose --env-file "$ENV_FILE" $COMPOSE_FILES config --images 2>/dev/null | sort -u) + +if [ -z "$IMAGES" ]; then + log "ERROR: Failed to extract images from docker-compose files" + write_status "error" "Failed to parse docker-compose configuration" + echo " ERROR: Failed to parse docker-compose configuration. Aborting upgrade." + exit 1 +fi + +log "Images to pull:" +echo "$IMAGES" | while read img; do log " - $img"; done # Backup existing .env file before making any changes if [ "$SKIP_BACKUP" != "true" ]; then if [ -f "$ENV_FILE" ]; then - echo "Creating backup of existing .env file to .env-$DATE" >>"$LOGFILE" + echo " Creating backup of .env file..." + log "Creating backup of .env file to .env-$DATE" cp "$ENV_FILE" "$ENV_FILE-$DATE" + log "Backup created: ${ENV_FILE}-${DATE}" else - echo "No existing .env file found to backup" >>"$LOGFILE" + log "WARNING: No existing .env file found to backup" fi fi -echo "Merging .env.production values into .env" >>"$LOGFILE" +log_section "Step 2/6: Updating environment configuration" +write_status "2" "Updating environment configuration" +echo "" +echo "2/6 Updating environment configuration..." +log "Merging .env.production values into .env" awk -F '=' '!seen[$1]++' "$ENV_FILE" /data/coolify/source/.env.production > "$ENV_FILE.tmp" && mv "$ENV_FILE.tmp" "$ENV_FILE" -echo ".env file merged successfully" >>"$LOGFILE" +log "Environment file merged successfully" update_env_var() { local key="$1" @@ -36,37 +110,173 @@ update_env_var() { # If variable "key=" exists but has no value, update the value of the existing line if grep -q "^${key}=$" "$ENV_FILE"; then sed -i "s|^${key}=$|${key}=${value}|" "$ENV_FILE" - echo " - Updated value of ${key} as the current value was empty" >>"$LOGFILE" + log "Updated ${key} (was empty)" # If variable "key=" doesn't exist, append it to the file with value elif ! grep -q "^${key}=" "$ENV_FILE"; then printf '%s=%s\n' "$key" "$value" >>"$ENV_FILE" - echo " - Added ${key} with default value as the variable was missing" >>"$LOGFILE" + log "Added ${key} (was missing)" fi } -echo "Checking and updating environment variables if necessary..." >>"$LOGFILE" +log "Checking environment variables..." update_env_var "PUSHER_APP_ID" "$(openssl rand -hex 32)" update_env_var "PUSHER_APP_KEY" "$(openssl rand -hex 32)" update_env_var "PUSHER_APP_SECRET" "$(openssl rand -hex 32)" +log "Environment variables check complete" +echo " Done." # Make sure coolify network exists # It is created when starting Coolify with docker compose +log "Checking Docker network 'coolify'..." if ! docker network inspect coolify >/dev/null 2>&1; then + log "Network 'coolify' does not exist, creating..." if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then - echo "Failed to create coolify network with ipv6. Trying without ipv6..." + log "Failed to create network with IPv6, trying without IPv6..." docker network create --attachable coolify 2>/dev/null + log "Network 'coolify' created without IPv6" + else + log "Network 'coolify' created with IPv6 support" fi +else + log "Network 'coolify' already exists" fi # Check if Docker config file exists DOCKER_CONFIG_MOUNT="" if [ -f /root/.docker/config.json ]; then DOCKER_CONFIG_MOUNT="-v /root/.docker/config.json:/root/.docker/config.json" + log "Docker config mount enabled: /root/.docker/config.json" fi -if [ -f /data/coolify/source/docker-compose.custom.yml ]; then - echo "docker-compose.custom.yml detected." >>"$LOGFILE" - docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock ${DOCKER_CONFIG_MOUNT} --rm ${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:${LATEST_HELPER_VERSION} bash -c "LATEST_IMAGE=${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --wait --wait-timeout 60" >>"$LOGFILE" 2>&1 +log_section "Step 3/6: Pulling Docker images" +write_status "3" "Pulling Docker images" +echo "" +echo "3/6 Pulling Docker images..." +echo " This may take a few minutes depending on your connection." + +# Also pull the helper image (not in compose files but needed for upgrade) +HELPER_IMAGE="${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:${LATEST_HELPER_VERSION}" +echo " - Pulling $HELPER_IMAGE..." +log "Pulling image: $HELPER_IMAGE" +if docker pull "$HELPER_IMAGE" >>"$LOGFILE" 2>&1; then + log "Successfully pulled $HELPER_IMAGE" else - docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock ${DOCKER_CONFIG_MOUNT} --rm ${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:${LATEST_HELPER_VERSION} bash -c "LATEST_IMAGE=${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --remove-orphans --wait --wait-timeout 60" >>"$LOGFILE" 2>&1 + log "ERROR: Failed to pull $HELPER_IMAGE" + write_status "error" "Failed to pull $HELPER_IMAGE" + echo " ERROR: Failed to pull $HELPER_IMAGE. Aborting upgrade." + exit 1 fi + +# Pull all images from compose config +# Using a for loop to avoid subshell issues with exit +for IMAGE in $IMAGES; do + if [ -n "$IMAGE" ]; then + echo " - Pulling $IMAGE..." + log "Pulling image: $IMAGE" + if docker pull "$IMAGE" >>"$LOGFILE" 2>&1; then + log "Successfully pulled $IMAGE" + else + log "ERROR: Failed to pull $IMAGE" + write_status "error" "Failed to pull $IMAGE" + echo " ERROR: Failed to pull $IMAGE. Aborting upgrade." + exit 1 + fi + fi +done + +log "All images pulled successfully" +echo " All images pulled successfully." + +log_section "Step 4/6: Stopping and restarting containers" +write_status "4" "Stopping containers" +echo "" +echo "4/6 Stopping containers and starting new ones..." +echo " This step will restart all Coolify containers." +echo " Check the log file for details: ${LOGFILE}" + +# From this point forward, we need to ensure the script continues even if +# the SSH connection is lost (which happens when coolify container stops) +# We use a subshell with nohup to ensure completion +log "Starting container restart sequence (detached)..." + +nohup bash -c " + LOGFILE='$LOGFILE' + STATUS_FILE='$STATUS_FILE' + DOCKER_CONFIG_MOUNT='$DOCKER_CONFIG_MOUNT' + REGISTRY_URL='$REGISTRY_URL' + LATEST_HELPER_VERSION='$LATEST_HELPER_VERSION' + LATEST_IMAGE='$LATEST_IMAGE' + + log() { + echo \"[\$(date '+%Y-%m-%d %H:%M:%S')] \$1\" >>\"\$LOGFILE\" + } + + write_status() { + echo \"\$1|\$2|\$(date -Iseconds)\" > \"\$STATUS_FILE\" + } + + # Stop and remove containers + for container in coolify coolify-db coolify-redis coolify-realtime; do + if docker ps -a --format '{{.Names}}' | grep -q \"^\${container}\$\"; then + log \"Stopping container: \${container}\" + docker stop \"\$container\" >>\"\$LOGFILE\" 2>&1 || true + log \"Removing container: \${container}\" + docker rm \"\$container\" >>\"\$LOGFILE\" 2>&1 || true + log \"Container \${container} stopped and removed\" + else + log \"Container \${container} not found (skipping)\" + fi + done + log \"Container cleanup complete\" + + # Start new containers + echo '' >>\"\$LOGFILE\" + echo '============================================================' >>\"\$LOGFILE\" + log 'Step 5/6: Starting new containers' + echo '============================================================' >>\"\$LOGFILE\" + write_status '5' 'Starting new containers' + + if [ -f /data/coolify/source/docker-compose.custom.yml ]; then + log 'Using custom docker-compose.yml' + log 'Running docker compose up with custom configuration...' + docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock \${DOCKER_CONFIG_MOUNT} --rm \${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:\${LATEST_HELPER_VERSION} bash -c \"LATEST_IMAGE=\${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --wait --wait-timeout 60\" >>\"\$LOGFILE\" 2>&1 + else + log 'Using standard docker-compose configuration' + log 'Running docker compose up...' + docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock \${DOCKER_CONFIG_MOUNT} --rm \${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-helper:\${LATEST_HELPER_VERSION} bash -c \"LATEST_IMAGE=\${LATEST_IMAGE} docker compose --project-name coolify --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --remove-orphans --wait --wait-timeout 60\" >>\"\$LOGFILE\" 2>&1 + fi + log 'Docker compose up completed' + + # Final log entry + echo '' >>\"\$LOGFILE\" + echo '============================================================' >>\"\$LOGFILE\" + log 'Step 6/6: Upgrade complete' + echo '============================================================' >>\"\$LOGFILE\" + write_status '6' 'Upgrade complete' + log 'Coolify upgrade completed successfully' + log \"Version: \${LATEST_IMAGE}\" + echo '' >>\"\$LOGFILE\" + echo '============================================================' >>\"\$LOGFILE\" + echo \"Upgrade completed: \$(date '+%Y-%m-%d %H:%M:%S')\" >>\"\$LOGFILE\" + echo '============================================================' >>\"\$LOGFILE\" + + # Clean up status file after a short delay to allow frontend to read completion + sleep 10 + rm -f \"\$STATUS_FILE\" + log 'Status file cleaned up' +" >>"$LOGFILE" 2>&1 & + +# Give the background process a moment to start +sleep 2 +log "Container restart sequence started in background (PID: $!)" +echo "" +echo "5/6 Containers are being restarted in the background..." +echo "6/6 Upgrade process initiated!" +echo "" +echo "==========================================" +echo " Coolify upgrade to ${LATEST_IMAGE} in progress" +echo "==========================================" +echo "" +echo " The upgrade will continue in the background." +echo " Coolify will be available again shortly." +echo " Log file: ${LOGFILE}"