diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php index ee3398b04..94651a3c1 100644 --- a/app/Actions/Application/StopApplication.php +++ b/app/Actions/Application/StopApplication.php @@ -39,7 +39,7 @@ public function handle(Application $application, bool $previewDeployments = fals foreach ($containersToStop as $containerName) { instant_remote_process(command: [ - "docker stop --time=30 $containerName", + "docker stop -t 30 $containerName", "docker rm -f $containerName", ], server: $server, throwError: false); } diff --git a/app/Actions/Application/StopApplicationOneServer.php b/app/Actions/Application/StopApplicationOneServer.php index 600b1cb9a..bf9fdee72 100644 --- a/app/Actions/Application/StopApplicationOneServer.php +++ b/app/Actions/Application/StopApplicationOneServer.php @@ -26,7 +26,7 @@ public function handle(Application $application, Server $server) if ($containerName) { instant_remote_process( [ - "docker stop --time=30 $containerName", + "docker stop -t 30 $containerName", "docker rm -f $containerName", ], $server diff --git a/app/Actions/Database/StartClickhouse.php b/app/Actions/Database/StartClickhouse.php index 7fdfe9aeb..6da5465c6 100644 --- a/app/Actions/Database/StartClickhouse.php +++ b/app/Actions/Database/StartClickhouse.php @@ -105,7 +105,7 @@ public function handle(StandaloneClickhouse $database) $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md"; $this->commands[] = "echo 'Pulling {$database->image} image.'"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; $this->commands[] = "echo 'Database started.'"; diff --git a/app/Actions/Database/StartDragonfly.php b/app/Actions/Database/StartDragonfly.php index d1bb119af..cd820523d 100644 --- a/app/Actions/Database/StartDragonfly.php +++ b/app/Actions/Database/StartDragonfly.php @@ -192,7 +192,7 @@ public function handle(StandaloneDragonfly $database) if ($this->database->enable_ssl) { $this->commands[] = "chown -R 999:999 $this->configuration_dir/ssl/server.key $this->configuration_dir/ssl/server.crt"; } - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; $this->commands[] = "echo 'Database started.'"; diff --git a/app/Actions/Database/StartKeydb.php b/app/Actions/Database/StartKeydb.php index 128469e24..863691e1e 100644 --- a/app/Actions/Database/StartKeydb.php +++ b/app/Actions/Database/StartKeydb.php @@ -208,7 +208,7 @@ public function handle(StandaloneKeydb $database) if ($this->database->enable_ssl) { $this->commands[] = "chown -R 999:999 $this->configuration_dir/ssl/server.key $this->configuration_dir/ssl/server.crt"; } - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; $this->commands[] = "echo 'Database started.'"; diff --git a/app/Actions/Database/StartMariadb.php b/app/Actions/Database/StartMariadb.php index 29dd7b8fe..498ba0b0b 100644 --- a/app/Actions/Database/StartMariadb.php +++ b/app/Actions/Database/StartMariadb.php @@ -209,7 +209,7 @@ public function handle(StandaloneMariadb $database) $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md"; $this->commands[] = "echo 'Pulling {$database->image} image.'"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; $this->commands[] = "echo 'Database started.'"; diff --git a/app/Actions/Database/StartMongodb.php b/app/Actions/Database/StartMongodb.php index 5982b68be..9565990c1 100644 --- a/app/Actions/Database/StartMongodb.php +++ b/app/Actions/Database/StartMongodb.php @@ -260,7 +260,7 @@ public function handle(StandaloneMongodb $database) $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md"; $this->commands[] = "echo 'Pulling {$database->image} image.'"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; if ($this->database->enable_ssl) { diff --git a/app/Actions/Database/StartMysql.php b/app/Actions/Database/StartMysql.php index c1df8d6db..337516405 100644 --- a/app/Actions/Database/StartMysql.php +++ b/app/Actions/Database/StartMysql.php @@ -210,7 +210,7 @@ public function handle(StandaloneMysql $database) $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md"; $this->commands[] = "echo 'Pulling {$database->image} image.'"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php index 1ae0d56a0..41e39c811 100644 --- a/app/Actions/Database/StartPostgresql.php +++ b/app/Actions/Database/StartPostgresql.php @@ -223,7 +223,7 @@ public function handle(StandalonePostgresql $database) $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md"; $this->commands[] = "echo 'Pulling {$database->image} image.'"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; if ($this->database->enable_ssl) { diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php index 4c99a0213..2eaf82fdd 100644 --- a/app/Actions/Database/StartRedis.php +++ b/app/Actions/Database/StartRedis.php @@ -205,7 +205,7 @@ public function handle(StandaloneRedis $database) if ($this->database->enable_ssl) { $this->commands[] = "chown -R 999:999 $this->configuration_dir/ssl/server.key $this->configuration_dir/ssl/server.crt"; } - $this->commands[] = "docker stop --time=10 $container_name 2>/dev/null || true"; + $this->commands[] = "docker stop -t 10 $container_name 2>/dev/null || true"; $this->commands[] = "docker rm -f $container_name 2>/dev/null || true"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; $this->commands[] = "echo 'Database started.'"; diff --git a/app/Actions/Database/StopDatabase.php b/app/Actions/Database/StopDatabase.php index 5c881e743..c024c14e1 100644 --- a/app/Actions/Database/StopDatabase.php +++ b/app/Actions/Database/StopDatabase.php @@ -49,7 +49,7 @@ private function stopContainer($database, string $containerName, int $timeout = { $server = $database->destination->server; instant_remote_process(command: [ - "docker stop --time=$timeout $containerName", + "docker stop -t $timeout $containerName", "docker rm -f $containerName", ], server: $server, throwError: false); } diff --git a/app/Actions/Proxy/StopProxy.php b/app/Actions/Proxy/StopProxy.php index 8f1b8af1c..04d031ec6 100644 --- a/app/Actions/Proxy/StopProxy.php +++ b/app/Actions/Proxy/StopProxy.php @@ -24,7 +24,7 @@ public function handle(Server $server, bool $forceStop = true, int $timeout = 30 } instant_remote_process(command: [ - "docker stop --time=$timeout $containerName 2>/dev/null || true", + "docker stop -t=$timeout $containerName 2>/dev/null || true", "docker rm -f $containerName 2>/dev/null || true", '# Wait for container to be fully removed', 'for i in {1..10}; do', diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php index 0bf763d78..a26e7daaa 100644 --- a/app/Actions/Server/UpdateCoolify.php +++ b/app/Actions/Server/UpdateCoolify.php @@ -3,6 +3,8 @@ namespace App\Actions\Server; use App\Models\Server; +use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Sleep; use Lorisleiva\Actions\Concerns\AsAction; @@ -29,7 +31,59 @@ public function handle($manual_update = false) return; } CleanupDocker::dispatch($this->server, false, false); - $this->latestVersion = get_latest_version_of_coolify(); + + // Fetch fresh version from CDN instead of using cache + try { + $response = Http::retry(3, 1000)->timeout(10) + ->get(config('constants.coolify.versions_url')); + + if ($response->successful()) { + $versions = $response->json(); + $this->latestVersion = data_get($versions, 'coolify.v4.version'); + } else { + // Fallback to cache if CDN unavailable + $cacheVersion = get_latest_version_of_coolify(); + + // Validate cache version against current running version + if ($cacheVersion && version_compare($cacheVersion, config('constants.coolify.version'), '<')) { + Log::error('Failed to fetch fresh version from CDN and cache is corrupted/outdated', [ + 'cached_version' => $cacheVersion, + 'current_version' => config('constants.coolify.version'), + ]); + throw new \Exception( + 'Cannot determine latest version: CDN unavailable and cache version '. + "({$cacheVersion}) is older than running version (".config('constants.coolify.version').')' + ); + } + + $this->latestVersion = $cacheVersion; + Log::warning('Failed to fetch fresh version from CDN (unsuccessful response), using validated cache', [ + 'version' => $cacheVersion, + ]); + } + } catch (\Throwable $e) { + $cacheVersion = get_latest_version_of_coolify(); + + // Validate cache version against current running version + if ($cacheVersion && version_compare($cacheVersion, config('constants.coolify.version'), '<')) { + Log::error('Failed to fetch fresh version from CDN and cache is corrupted/outdated', [ + 'error' => $e->getMessage(), + 'cached_version' => $cacheVersion, + 'current_version' => config('constants.coolify.version'), + ]); + throw new \Exception( + 'Cannot determine latest version: CDN unavailable and cache version '. + "({$cacheVersion}) is older than running version (".config('constants.coolify.version').')' + ); + } + + $this->latestVersion = $cacheVersion; + Log::warning('Failed to fetch fresh version from CDN, using validated cache', [ + 'error' => $e->getMessage(), + 'version' => $cacheVersion, + ]); + } + $this->currentVersion = config('constants.coolify.version'); if (! $manual_update) { if (! $settings->is_auto_update_enabled) { @@ -42,6 +96,20 @@ public function handle($manual_update = false) return; } } + + // ALWAYS check for downgrades (even for manual updates) + if (version_compare($this->latestVersion, $this->currentVersion, '<')) { + Log::error('Downgrade prevented', [ + 'target_version' => $this->latestVersion, + 'current_version' => $this->currentVersion, + 'manual_update' => $manual_update, + ]); + throw new \Exception( + "Cannot downgrade from {$this->currentVersion} to {$this->latestVersion}. ". + 'If you need to downgrade, please do so manually via Docker commands.' + ); + } + $this->update(); $settings->new_version_available = false; $settings->save(); @@ -56,8 +124,9 @@ private function update() $image = config('constants.coolify.registry_url').'/coollabsio/coolify:'.$this->latestVersion; instant_remote_process(["docker pull -q $image"], $this->server, false); + $upgradeScriptUrl = config('constants.coolify.upgrade_script_url'); remote_process([ - 'curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh', + "curl -fsSL {$upgradeScriptUrl} -o /data/coolify/source/upgrade.sh", "bash /data/coolify/source/upgrade.sh $this->latestVersion", ], $this->server); } diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php index 3f4e96479..23b41e3f2 100644 --- a/app/Actions/Service/StopService.php +++ b/app/Actions/Service/StopService.php @@ -54,7 +54,7 @@ private function stopContainersInParallel(array $containersToStop, Server $serve $timeout = count($containersToStop) > 5 ? 10 : 30; $commands = []; $containerList = implode(' ', $containersToStop); - $commands[] = "docker stop --time=$timeout $containerList"; + $commands[] = "docker stop -t $timeout $containerList"; $commands[] = "docker rm -f $containerList"; instant_remote_process( command: $commands, diff --git a/app/Console/Commands/NotifyDemo.php b/app/Console/Commands/NotifyDemo.php index 990a03869..8e9251ac0 100644 --- a/app/Console/Commands/NotifyDemo.php +++ b/app/Console/Commands/NotifyDemo.php @@ -56,7 +56,7 @@ private function showHelp() php artisan app:demo-notify {channel}

-
Channels:
+
Channels: