diff --git a/app/Actions/Proxy/CheckConfiguration.php b/app/Actions/Proxy/CheckConfiguration.php index 1526c9728..e244296c5 100644 --- a/app/Actions/Proxy/CheckConfiguration.php +++ b/app/Actions/Proxy/CheckConfiguration.php @@ -16,9 +16,12 @@ class CheckConfiguration "cat $proxy_path/docker-compose.yml", ], $server, false); - if ($reset || is_null($proxy_configuration)) { + if ($reset || !$proxy_configuration || is_null($proxy_configuration)) { $proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value; } + if (!$proxy_configuration || is_null($proxy_configuration)) { + throw new \Exception("Could not generate proxy configuration"); + } return $proxy_configuration; } } diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php index 7af5aa019..944480ef2 100644 --- a/app/Actions/Proxy/StartProxy.php +++ b/app/Actions/Proxy/StartProxy.php @@ -51,9 +51,9 @@ class StartProxy "cd $proxy_path", "echo '####### Creating Docker Compose file...'", "echo '####### Pulling docker image...'", - 'docker compose pull', + 'docker compose pull || docker-compose pull', "echo '####### Stopping existing coolify-proxy...'", - "docker compose down -v --remove-orphans > /dev/null 2>&1 || true", + "docker compose down -v --remove-orphans > /dev/null 2>&1 || docker-compose down -v --remove-orphans > /dev/null 2>&1 || true", "command -v fuser >/dev/null || command -v lsof >/dev/null || echo '####### Could not kill existing processes listening on port 80 & 443. Please stop the process holding these ports...'", "command -v lsof >/dev/null && lsof -nt -i:80 | xargs -r kill -9 || true", "command -v lsof >/dev/null && lsof -nt -i:443 | xargs -r kill -9 || true", @@ -63,7 +63,7 @@ class StartProxy "systemctl disable apache2 > /dev/null 2>&1 || true", "systemctl disable apache > /dev/null 2>&1 || true", "echo '####### Starting coolify-proxy...'", - 'docker compose up -d --remove-orphans', + 'docker compose up -d --remove-orphans || docker-compose up -d --remove-orphans', "echo '####### Proxy installed successfully...'" ]; if (!$async) { diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index 39d0718db..2fb12d34c 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -7,7 +7,7 @@ use App\Models\StandaloneDocker; class InstallDocker { - public function __invoke(Server $server, bool $instant = false) + public function __invoke(Server $server) { $dockerVersion = '24.0'; $config = base64_encode('{ @@ -55,9 +55,6 @@ class InstallDocker "echo '####### Done!'" ]; } - if ($instant) { - return instant_remote_process($command, $server); - } return remote_process($command, $server); } } diff --git a/app/Data/CoolifyTaskArgs.php b/app/Data/CoolifyTaskArgs.php index 07d7c0c81..f73fd6318 100644 --- a/app/Data/CoolifyTaskArgs.php +++ b/app/Data/CoolifyTaskArgs.php @@ -17,8 +17,11 @@ class CoolifyTaskArgs extends Data public string $type, public ?string $type_uuid = null, public ?Model $model = null, - public string $status = ProcessStatus::QUEUED->value, + public ?string $status = null , public bool $ignore_errors = false, ) { + if(is_null($status)){ + $this->status = ProcessStatus::QUEUED->value; + } } } diff --git a/app/Http/Livewire/Boarding/Index.php b/app/Http/Livewire/Boarding/Index.php index fc1784383..c1ec202cf 100644 --- a/app/Http/Livewire/Boarding/Index.php +++ b/app/Http/Livewire/Boarding/Index.php @@ -9,7 +9,6 @@ use App\Models\Server; use App\Models\Team; use Illuminate\Support\Collection; use Livewire\Component; -use Visus\Cuid2\Cuid2; class Index extends Component { @@ -40,8 +39,8 @@ class Index extends Component public bool $dockerInstallationStarted = false; - public string $localhostPublicKey; - public bool $localhostReachable = true; + public string $serverPublicKey; + public bool $serverReachable = true; public function mount() { @@ -70,14 +69,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== public function restartBoarding() { - // if ($this->selectedServerType !== 'localhost') { - // if ($this->createdServer) { - // $this->createdServer->delete(); - // } - // if ($this->createdPrivateKey) { - // $this->createdPrivateKey->delete(); - // } - // } return redirect()->route('boarding'); } public function skipBoarding() @@ -98,7 +89,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== if (!$this->createdServer) { return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.'); } - $this->localhostPublicKey = $this->createdServer->privateKey->publicKey(); + $this->serverPublicKey = $this->createdServer->privateKey->publicKey(); return $this->validateServer('localhost'); } elseif ($this->selectedServerType === 'remote') { $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); @@ -123,6 +114,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== return; } $this->selectedExistingPrivateKey = $this->createdServer->privateKey->id; + $this->serverPublicKey = $this->createdServer->privateKey->publicKey(); $this->validateServer(); } public function getProxyType() @@ -201,11 +193,11 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== instant_remote_process(['uptime'], $this->createdServer, true); - $this->createdServer->settings->update([ + $this->createdServer->settings()->update([ 'is_reachable' => true, ]); } catch (\Throwable $e) { - $this->localhostReachable = false; + $this->serverReachable = false; return handleError(error: $e, customErrorMessage: $customErrorMessage, livewire: $this); } @@ -216,8 +208,12 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== $this->currentState = 'install-docker'; throw new \Exception('Docker version is not supported or not installed.'); } - $this->dockerInstalledOrSkipped(); + $this->createdServer->settings()->update([ + 'is_usable' => true, + ]); + $this->getProxyType(); } catch (\Throwable $e) { + $this->dockerInstallationStarted = false; return handleError(error: $e, customErrorMessage: $customErrorMessage, livewire: $this); } } @@ -229,10 +225,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== } public function dockerInstalledOrSkipped() { - $this->createdServer->settings->update([ - 'is_usable' => true, - ]); - $this->getProxyType(); + $this->validateServer(); } public function selectProxy(string|null $proxyType = null) { diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index b7c76363c..527dcad67 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -86,7 +86,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted $this->server->team->notify(new ContainerRestarted('coolify-proxy', $this->server)); } } else { - ray($foundProxyContainer); $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); $this->server->save(); } @@ -198,94 +197,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted $url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/database/" . $database->uuid; $this->server->team->notify(new ContainerStopped($containerName, $this->server, $url)); } - - - - - - - - - - - - - return; - foreach ($applications as $application) { - $uuid = data_get($application, 'uuid'); - $id = data_get($application, 'id'); - $foundContainer = $containers->filter(function ($value, $key) use ($id, $uuid) { - $labels = data_get($value, 'Config.Labels'); - $labels = Arr::undot(format_docker_labels_to_json($labels)); - $labelId = data_get($labels, 'coolify.applicationId'); - if ($labelId == $id) { - return $value; - } - $isPR = Str::startsWith(data_get($value, 'Name'), "/$uuid"); - $isPR = Str::contains(data_get($value, 'Name'), "-pr-"); - if ($isPR) { - return false; - } - return $value; - })->first(); - if ($foundContainer) { - $containerStatus = data_get($foundContainer, 'State.Status'); - $databaseStatus = data_get($application, 'status'); - if ($containerStatus !== $databaseStatus) { - $application->update(['status' => $containerStatus]); - } - } else { - $databaseStatus = data_get($application, 'status'); - if ($databaseStatus !== 'exited') { - $application->update(['status' => 'exited']); - $name = data_get($application, 'name'); - $fqdn = data_get($application, 'fqdn'); - $containerName = $name ? "$name ($fqdn)" : $fqdn; - $project = data_get($application, 'environment.project'); - $environment = data_get($application, 'environment'); - $url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/application/" . $application->uuid; - $this->server->team->notify(new ContainerStopped($containerName, $this->server, $url)); - } - } - $previews = $application->previews; - foreach ($previews as $preview) { - $foundContainer = $containers->filter(function ($value, $key) use ($id, $uuid, $preview) { - $labels = data_get($value, 'Config.Labels'); - $labels = Arr::undot(format_docker_labels_to_json($labels)); - $labelId = data_get($labels, 'coolify.applicationId'); - if ($labelId == "$id-pr-{$preview->id}") { - return $value; - } - return Str::startsWith(data_get($value, 'Name'), "/$uuid-pr-{$preview->id}"); - })->first(); - } - } - foreach ($databases as $database) { - $uuid = data_get($database, 'uuid'); - $foundContainer = $containers->filter(function ($value, $key) use ($uuid) { - return Str::startsWith(data_get($value, 'Name'), "/$uuid"); - })->first(); - - if ($foundContainer) { - $containerStatus = data_get($foundContainer, 'State.Status'); - $databaseStatus = data_get($database, 'status'); - if ($containerStatus !== $databaseStatus) { - $database->update(['status' => $containerStatus]); - } - } else { - $databaseStatus = data_get($database, 'status'); - if ($databaseStatus !== 'exited') { - $database->update(['status' => 'exited']); - $name = data_get($database, 'name'); - $containerName = $name; - $project = data_get($database, 'environment.project'); - $environment = data_get($database, 'environment'); - $url = base_url() . '/project/' . $project->uuid . "/" . $environment->name . "/database/" . $database->uuid; - $this->server->team->notify(new ContainerStopped($containerName, $this->server, $url)); - } - } - } - // TODO Monitor other containers not managed by Coolify } catch (\Throwable $e) { send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage()); ray($e->getMessage()); diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index efac09097..f97fbc77e 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -14,7 +14,7 @@ class DeploymentFailed extends Notification implements ShouldQueue { use Queueable; - public $tries = 5; + public $tries = 1; public Application $application; public ?ApplicationPreview $preview = null; diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index 3b2d6e17f..053ae7a2b 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -14,7 +14,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue { use Queueable; - public $tries = 5; + public $tries = 1; public Application $application; public ApplicationPreview|null $preview = null; diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index 90ac92304..064c347d0 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -13,7 +13,7 @@ class StatusChanged extends Notification implements ShouldQueue { use Queueable; - public $tries = 5; + public $tries = 1; public Application $application; public string $application_name; diff --git a/app/Notifications/Channels/EmailChannel.php b/app/Notifications/Channels/EmailChannel.php index e0f9edac0..057d50dc0 100644 --- a/app/Notifications/Channels/EmailChannel.php +++ b/app/Notifications/Channels/EmailChannel.php @@ -6,27 +6,34 @@ use Exception; use Illuminate\Mail\Message; use Illuminate\Notifications\Notification; use Illuminate\Support\Facades\Mail; +use Log; class EmailChannel { public function send(SendsEmail $notifiable, Notification $notification): void { - $this->bootConfigs($notifiable); - $recepients = $notifiable->getRecepients($notification); + try { + $this->bootConfigs($notifiable); + $recepients = $notifiable->getRecepients($notification); + ray($recepients); + if (count($recepients) === 0) { + throw new Exception('No email recipients found'); + } - if (count($recepients) === 0) { - throw new Exception('No email recipients found'); + $mailMessage = $notification->toMail($notifiable); + Mail::send( + [], + [], + fn (Message $message) => $message + ->to($recepients) + ->subject($mailMessage->subject) + ->html((string)$mailMessage->render()) + ); + } catch (Exception $e) { + ray($e->getMessage()); + send_internal_notification("EmailChannel error: {$e->getMessage()}. Failed to send email to: " . implode(', ', $recepients) . " with subject: {$mailMessage->subject}"); + throw $e; } - - $mailMessage = $notification->toMail($notifiable); - Mail::send( - [], - [], - fn (Message $message) => $message - ->to($recepients) - ->subject($mailMessage->subject) - ->html((string)$mailMessage->render()) - ); } private function bootConfigs($notifiable): void diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php index 480fe2cb0..25fd08ff8 100644 --- a/app/Notifications/Container/ContainerRestarted.php +++ b/app/Notifications/Container/ContainerRestarted.php @@ -12,7 +12,7 @@ class ContainerRestarted extends Notification implements ShouldQueue { use Queueable; - public $tries = 5; + public $tries = 1; public function __construct(public string $name, public Server $server, public ?string $url = null) diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index 960232f9c..482b27977 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -3,8 +3,6 @@ namespace App\Notifications\Database; use App\Models\ScheduledDatabaseBackup; -use App\Notifications\Channels\DiscordChannel; -use App\Notifications\Channels\EmailChannel; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -14,7 +12,7 @@ class BackupFailed extends Notification implements ShouldQueue { use Queueable; - public $tries = 5; + public $tries = 1; public string $name; public string $frequency; diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index bac96ae35..0378baf96 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -3,8 +3,6 @@ namespace App\Notifications\Database; use App\Models\ScheduledDatabaseBackup; -use App\Notifications\Channels\DiscordChannel; -use App\Notifications\Channels\EmailChannel; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; @@ -14,7 +12,7 @@ class BackupSuccess extends Notification implements ShouldQueue { use Queueable; - public $tries = 5; + public $tries = 1; public string $name; public string $frequency; diff --git a/bootstrap/helpers/remoteProcess.php b/bootstrap/helpers/remoteProcess.php index 5982b46d8..7bf194711 100644 --- a/bootstrap/helpers/remoteProcess.php +++ b/bootstrap/helpers/remoteProcess.php @@ -18,12 +18,14 @@ use Spatie\Activitylog\Contracts\Activity; function remote_process( array $command, Server $server, - string $type = ActivityTypes::INLINE->value, + ?string $type = null, ?string $type_uuid = null, ?Model $model = null, bool $ignore_errors = false, ): Activity { - + if (is_null($type)) { + $type = ActivityTypes::INLINE->value; + } $command_string = implode("\n", $command); if (auth()->user()) { $teams = auth()->user()->teams->pluck('id'); diff --git a/bootstrap/helpers/subscriptions.php b/bootstrap/helpers/subscriptions.php index ac41b1a1d..9ea76ec9b 100644 --- a/bootstrap/helpers/subscriptions.php +++ b/bootstrap/helpers/subscriptions.php @@ -138,5 +138,6 @@ function allowedPathsForBoardingAccounts() ...allowedPathsForUnsubscribedAccounts(), 'boarding', 'livewire/message/boarding.index', + 'livewire/message/activity-monitor' ]; } diff --git a/config/sentry.php b/config/sentry.php index 45b51b89b..82a9d4d43 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.42', + 'release' => '4.0.0-beta.43', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index 270d2ee5f..9a953c5c7 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ true, ]) -
Start self-hosting without limits with + our + OSS version. Same features as the paid version, but you have to manage by yourself.
+- - Free - - - Still Free - -
- - billed monthly - - - billed annually - - Get - Started -Start self-hosting without limits with our - OSS - version.
-$5 - /month + /month + VAT $4 - /month + /month + VAT
@@ -139,8 +95,8 @@Private Keys are used to connect to a remote server through a secure shell, called SSH.
@@ -214,10 +225,10 @@ Could not find Docker Engine on your server. Do you want me to install it for you?