diff --git a/app/Actions/Server/InstallLogDrain.php b/app/Actions/Server/InstallLogDrain.php
index e43642e7a..2a1b03260 100644
--- a/app/Actions/Server/InstallLogDrain.php
+++ b/app/Actions/Server/InstallLogDrain.php
@@ -198,7 +198,7 @@ Files:
}
$restart_command = [
"echo 'Stopping old Fluent Bit'",
- "cd $config_path && docker rm -f coolify-log-drain || true",
+ "cd $config_path && docker compose down --remove-orphans || true",
"echo 'Starting Fluent Bit'",
"cd $config_path && docker compose up -d --remove-orphans",
];
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index 1b14e7e12..ccf1bba3d 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -618,6 +618,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
}
} else {
$this->dockerImageTag = str($this->commit)->substr(0, 128);
+ if ($this->application->docker_registry_image_tag) {
+ $this->dockerImageTag = $this->application->docker_registry_image_tag;
+ }
if ($this->application->docker_registry_image_name) {
$this->build_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}-build");
$this->production_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}");
diff --git a/app/Livewire/Admin/Index.php b/app/Livewire/Admin/Index.php
index 3c13cd771..4ff4ff21b 100644
--- a/app/Livewire/Admin/Index.php
+++ b/app/Livewire/Admin/Index.php
@@ -11,6 +11,9 @@ class Index extends Component
public $users = [];
public function mount()
{
+ if (!isCloud()) {
+ return redirect()->route('dashboard');
+ }
if (auth()->user()->id !== 0 && session('adminToken') === null) {
return redirect()->route('dashboard');
}
diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php
index eee62c93d..8cb1dd7d2 100644
--- a/app/Livewire/Boarding/Index.php
+++ b/app/Livewire/Boarding/Index.php
@@ -3,6 +3,7 @@
namespace App\Livewire\Boarding;
use App\Actions\Server\InstallDocker;
+use App\Enums\ProxyTypes;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server;
@@ -121,15 +122,16 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
- $this->validateServer();
+ $this->installServer();
}
public function getProxyType()
{
- $proxyTypeSet = $this->createdServer->proxy->type;
- if (!$proxyTypeSet) {
- $this->currentState = 'select-proxy';
- return;
- }
+ $this->selectProxy(ProxyTypes::TRAEFIK_V2->value);
+ // $proxyTypeSet = $this->createdServer->proxy->type;
+ // if (!$proxyTypeSet) {
+ // $this->currentState = 'select-proxy';
+ // return;
+ // }
$this->getProjects();
}
public function selectExistingPrivateKey()
@@ -193,7 +195,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
$this->createdServer->settings->save();
$this->createdServer->addInitialNetwork();
- $this->validateServer();
+ $this->currentState = 'validate-server';
}
public function installServer()
{
@@ -219,7 +221,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if (is_null($dockerVersion)) {
- $this->currentState = 'install-docker';
+ $this->currentState = 'validate-server';
throw new \Exception('Docker not found or old version is installed.');
}
$this->createdServer->settings()->update([
@@ -227,27 +229,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
]);
$this->getProxyType();
} catch (\Throwable $e) {
- // $this->dockerInstallationStarted = false;
return handleError(error: $e, livewire: $this);
}
}
- public function installDocker()
- {
- try {
- $this->dockerInstallationStarted = true;
- $activity = InstallDocker::run($this->createdServer);
- $this->dispatch('installDocker');
- $this->dispatch('activityMonitor', $activity->id);
- } catch (\Throwable $e) {
- $this->dockerInstallationStarted = false;
- return handleError(error: $e, livewire: $this);
- }
- }
- public function dockerInstalledOrSkipped()
- {
- $this->validateServer();
- }
- public function selectProxy(string|null $proxyType = null)
+ public function selectProxy(?string $proxyType = null)
{
if (!$proxyType) {
return $this->getProjects();
diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php
index 696ae09c4..a44cd18af 100644
--- a/app/Livewire/Dashboard.php
+++ b/app/Livewire/Dashboard.php
@@ -22,6 +22,7 @@ class Dashboard extends Component
}
public function cleanup_queue()
{
+ $this->dispatch('success', 'Cleanup started.');
Artisan::queue('app:init', [
'--cleanup-deployments' => 'true'
]);
diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php
index 1b19c445a..01ab13c4e 100644
--- a/app/Livewire/Project/Application/Heading.php
+++ b/app/Livewire/Project/Application/Heading.php
@@ -56,15 +56,15 @@ class Heading extends Component
return;
}
if ($this->application->destination->server->isSwarm() && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy', 'To deploy to a Swarm cluster you must set a Docker image name first.');
+ $this->dispatch('error', 'Failed to deploy.', 'To deploy to a Swarm cluster you must set a Docker image name first.');
return;
}
if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy', 'To use a build server, you must first set a Docker image.
More information here: documentation');
+ $this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.
More information here: documentation');
return;
}
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy', 'To deploy to more than one server, you must first set a Docker image.
More information here: documentation');
+ $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation');
return;
}
$this->setDeploymentUuid();
@@ -103,7 +103,7 @@ class Heading extends Component
public function restart()
{
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy', 'To deploy to more than one server, you must first set a Docker image.
More information here: documentation');
+ $this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation');
return;
}
$this->setDeploymentUuid();
diff --git a/app/Livewire/Project/Service/Index.php b/app/Livewire/Project/Service/Index.php
index 21009cb44..ede42c2c7 100644
--- a/app/Livewire/Project/Service/Index.php
+++ b/app/Livewire/Project/Service/Index.php
@@ -27,12 +27,12 @@ class Index extends Component
$this->parameters = get_route_parameters();
$this->query = request()->query();
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
- $service = $this->service->applications()->whereName($this->parameters['service_name'])->first();
+ $service = $this->service->applications()->whereUuid($this->parameters['stack_service_uuid'])->first();
if ($service) {
$this->serviceApplication = $service;
$this->serviceApplication->getFilesFromServer();
} else {
- $this->serviceDatabase = $this->service->databases()->whereName($this->parameters['service_name'])->first();
+ $this->serviceDatabase = $this->service->databases()->whereUuid($this->parameters['stack_service_uuid'])->first();
$this->serviceDatabase->getFilesFromServer();
}
$this->s3s = currentTeam()->s3s;
diff --git a/app/Livewire/Project/Shared/Destination.php b/app/Livewire/Project/Shared/Destination.php
index cf5e2632f..3d816149b 100644
--- a/app/Livewire/Project/Shared/Destination.php
+++ b/app/Livewire/Project/Shared/Destination.php
@@ -37,10 +37,13 @@ class Destination extends Component
$this->networks = $this->networks->reject(function ($network) use ($all_networks) {
return $all_networks->pluck('id')->contains($network->id);
});
-
}
public function redeploy(int $network_id, int $server_id)
{
+ if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) {
+ $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation');
+ return;
+ }
$deployment_uuid = new Cuid2(7);
$server = Server::find($server_id);
$destination = StandaloneDocker::find($network_id);
diff --git a/app/Livewire/Server/Proxy/Status.php b/app/Livewire/Server/Proxy/Status.php
index a41994c8f..bd0ffe431 100644
--- a/app/Livewire/Server/Proxy/Status.php
+++ b/app/Livewire/Server/Proxy/Status.php
@@ -12,7 +12,7 @@ class Status extends Component
public Server $server;
public bool $polling = false;
public int $numberOfPolls = 0;
- protected $listeners = ['proxyStatusUpdated', 'startProxyPolling'];
+ protected $listeners = ['proxyStatusUpdated' => '$refresh', 'startProxyPolling'];
public function startProxyPolling()
{
diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php
index e5d2a4b39..4d37feca2 100644
--- a/app/Livewire/Server/ValidateAndInstall.php
+++ b/app/Livewire/Server/ValidateAndInstall.php
@@ -2,6 +2,7 @@
namespace App\Livewire\Server;
+use App\Actions\Proxy\StartProxy;
use App\Models\Server;
use Livewire\Component;
@@ -14,18 +15,23 @@ class ValidateAndInstall extends Component
public $uptime = null;
public $supported_os_type = null;
public $docker_installed = null;
+ public $docker_compose_installed = null;
public $docker_version = null;
+ public $proxy_started = false;
public $error = null;
protected $listeners = ['validateServer' => 'init', 'validateDockerEngine', 'validateServerNow' => 'validateServer'];
public function init(bool $install = true)
{
+
$this->install = $install;
$this->uptime = null;
$this->supported_os_type = null;
$this->docker_installed = null;
$this->docker_version = null;
+ $this->docker_compose_installed = null;
+ $this->proxy_started = null;
$this->error = null;
$this->number_of_tries = 0;
$this->dispatch('validateServerNow');
@@ -43,6 +49,11 @@ class ValidateAndInstall extends Component
if ($swarmInstalled) {
$this->dispatch('success', 'Docker Swarm is initiated.');
}
+ } else {
+ $proxy = StartProxy::run($this->server);
+ if ($proxy) {
+ $this->proxy_started = true;
+ }
}
} catch (\Throwable $e) {
return handleError($e, $this);
@@ -67,9 +78,9 @@ class ValidateAndInstall extends Component
public function validateDockerEngine()
{
$this->docker_installed = $this->server->validateDockerEngine();
- if (!$this->docker_installed) {
+ $this->docker_compose_installed = $this->server->validateDockerCompose();
+ if (!$this->docker_installed || !$this->docker_compose_installed) {
if ($this->install) {
- ray($this->number_of_tries, $this->max_tries);
if ($this->number_of_tries == $this->max_tries) {
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: documentation.';
return;
diff --git a/app/Models/Application.php b/app/Models/Application.php
index 959d06d7f..0ba1d24d1 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -200,9 +200,6 @@ class Application extends BaseModel
set: fn ($value) => $value === "" ? null : $value,
);
}
-
- // Normal Deployments
-
public function portsMappingsArray(): Attribute
{
return Attribute::make(
@@ -214,7 +211,7 @@ class Application extends BaseModel
}
public function realStatus()
{
- return $this->getRawOriginal('status');
+ return $this->getRawOriginal('status');
}
public function status(): Attribute
{
diff --git a/app/Models/Server.php b/app/Models/Server.php
index bdbb0309d..e4a7b895a 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -443,6 +443,21 @@ class Server extends BaseModel
$this->validateCoolifyNetwork(isSwarm: false, isBuildServer: $this->settings->is_build_server);
return true;
}
+ public function validateDockerCompose($throwError = false)
+ {
+ $dockerCompose = instant_remote_process(["docker compose version"], $this, false);
+ if (is_null($dockerCompose)) {
+ $this->settings->is_usable = false;
+ $this->settings->save();
+ if ($throwError) {
+ throw new \Exception('Server is not usable. Docker Compose is not installed.');
+ }
+ return false;
+ }
+ $this->settings->is_usable = true;
+ $this->settings->save();
+ return true;
+ }
public function validateDockerSwarm()
{
$swarmStatus = instant_remote_process(["docker info|grep -i swarm"], $this, false);
diff --git a/bootstrap/helpers/constants.php b/bootstrap/helpers/constants.php
index 9b16ebfed..134cc6aad 100644
--- a/bootstrap/helpers/constants.php
+++ b/bootstrap/helpers/constants.php
@@ -13,6 +13,11 @@ const VALID_CRON_STRINGS = [
const RESTART_MODE = 'unless-stopped';
const DATABASE_DOCKER_IMAGES = [
+ 'bitnami/mariadb',
+ 'bitnami/mongodb',
+ 'bitnami/mysql',
+ 'bitnami/postgresql',
+ 'bitnami/redis',
'mysql',
'mariadb',
'postgres',
diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php
index 3ebec43b9..eb0898bfd 100644
--- a/bootstrap/helpers/docker.php
+++ b/bootstrap/helpers/docker.php
@@ -349,18 +349,8 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
foreach ($matches as $match) {
$option = $match[1];
$value = isset($match[2]) && $match[2] !== '' ? $match[2] : true;
- if ($list_options->contains($option)) {
- $value = explode(',', $value);
- }
- if (array_key_exists($option, $options)) {
- if (is_array($options[$option])) {
- $options[$option][] = $value;
- } else {
- $options[$option] = [$options[$option], $value];
- }
- } else {
- $options[$option] = $value;
- }
+ $options[$option][] = $value;
+ $options[$option] = array_unique($options[$option]);
}
$options = collect($options);
// Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js
@@ -370,7 +360,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
}
if ($option === '--ulimit') {
$ulimits = collect([]);
- collect($value)->map(function ($ulimit) use ($ulimits){
+ collect($value)->map(function ($ulimit) use ($ulimits) {
$ulimit = explode('=', $ulimit);
$type = $ulimit[0];
$limits = explode(':', $ulimit[1]);
@@ -381,7 +371,6 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
'soft' => $soft_limit,
'hard' => $hard_limit
]);
-
} else {
$soft_limit = $ulimit[1];
$ulimits->put($type, [
diff --git a/config/sentry.php b/config/sentry.php
index 5f2ea6fb6..4a2eff3f2 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.212',
+ 'release' => '4.0.0-beta.213',
// 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 01e2a62f9..b1372fd9d 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
- Port {{ $port }}
+ {{ $application->destination->server->ip }}:{{ explode(':', $port)[0] }}
+ @if (count($application->additional_servers) > 0)
+ @foreach ($application->additional_servers as $server)
+