diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php index c2d7e8a80..973296380 100644 --- a/app/Actions/Database/StartPostgresql.php +++ b/app/Actions/Database/StartPostgresql.php @@ -21,6 +21,7 @@ class StartPostgresql $this->configuration_dir = database_configuration_dir() . '/' . $container_name; $this->commands = [ + "echo '####### Starting {$database->name}.'", "mkdir -p $this->configuration_dir", "mkdir -p $this->configuration_dir/docker-entrypoint-initdb.d/" ]; @@ -96,6 +97,7 @@ class StartPostgresql $readme = generate_readme_file($this->database->name, now()); $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md"; $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; + $this->commands[] = "echo '####### {$database->name} started.'"; return remote_process($this->commands, $server); } diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php index aafeb2f3e..ab5d1733e 100644 --- a/app/Actions/Proxy/StartProxy.php +++ b/app/Actions/Proxy/StartProxy.php @@ -2,8 +2,6 @@ namespace App\Actions\Proxy; -use App\Enums\ProxyStatus; -use App\Enums\ProxyTypes; use App\Models\Server; use Illuminate\Support\Str; use Lorisleiva\Actions\Concerns\AsAction; diff --git a/app/Actions/Service/StartService.php b/app/Actions/Service/StartService.php index e82040e74..e9c0ba546 100644 --- a/app/Actions/Service/StartService.php +++ b/app/Actions/Service/StartService.php @@ -11,7 +11,7 @@ class StartService public function handle(Service $service) { $workdir = service_configuration_dir() . "/{$service->uuid}"; - $commands[] = "echo 'Starting service {$service->name} on {$service->server->name}.'"; + $commands[] = "echo '####### Starting service {$service->name} on {$service->server->name}.'"; $commands[] = "mkdir -p $workdir"; $commands[] = "cd $workdir"; @@ -22,11 +22,10 @@ class StartService foreach ($envs as $env) { $commands[] = "echo '{$env->key}={$env->value}' >> .env"; } - $commands[] = "echo 'Pulling images and starting containers...'"; - $commands[] = "docker compose pull"; - $commands[] = "docker compose up -d"; - $commands[] = "echo 'Waiting for containers to start...'"; - $commands[] = "sleep 5"; + $commands[] = "echo '####### Pulling images.'"; + $commands[] = "docker compose pull --quiet"; + $commands[] = "echo '####### Starting containers.'"; + $commands[] = "docker compose up -d >/dev/null 2>&1"; $commands[] = "docker network connect $service->uuid coolify-proxy 2>/dev/null || true"; $activity = remote_process($commands, $service->server); return $activity; diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php index 821428b28..746ab6bf7 100644 --- a/app/Actions/Service/StopService.php +++ b/app/Actions/Service/StopService.php @@ -20,6 +20,6 @@ class StopService instant_remote_process(["docker rm -f {$db->name}-{$service->uuid}"], $service->server); $db->update(['status' => 'exited']); } - instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy 2>/dev/null"], $service->server); + instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy 2>/dev/null"], $service->server, false); } } diff --git a/app/Http/Livewire/Destination/Form.php b/app/Http/Livewire/Destination/Form.php index 632a26370..fbce335e7 100644 --- a/app/Http/Livewire/Destination/Form.php +++ b/app/Http/Livewire/Destination/Form.php @@ -38,7 +38,7 @@ class Form extends Component $this->destination->delete(); return redirect()->route('dashboard'); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } } diff --git a/app/Http/Livewire/Project/Application/General.php b/app/Http/Livewire/Project/Application/General.php index affc4bcab..b4e122ec8 100644 --- a/app/Http/Livewire/Project/Application/General.php +++ b/app/Http/Livewire/Project/Application/General.php @@ -52,8 +52,6 @@ class General extends Component 'application.ports_exposes' => 'required', 'application.ports_mappings' => 'nullable', 'application.dockerfile' => 'nullable', - 'application.dockercompose_raw' => 'nullable', - 'application.dockercompose' => 'nullable', ]; protected $validationAttributes = [ 'application.name' => 'name', @@ -72,8 +70,6 @@ class General extends Component 'application.ports_exposes' => 'Ports exposes', 'application.ports_mappings' => 'Ports mappings', 'application.dockerfile' => 'Dockerfile', - 'application.dockercompose_raw' => 'Docker Compose (raw)', - 'application.dockercompose' => 'Docker Compose', ]; @@ -165,10 +161,6 @@ class General extends Component if ($this->application->publish_directory && $this->application->publish_directory !== '/') { $this->application->publish_directory = rtrim($this->application->publish_directory, '/'); } - if (data_get($this->application, 'dockercompose_raw')) { - $details = generateServiceFromTemplate( $this->application); - $this->application->dockercompose = data_get($details, 'dockercompose'); - } $this->application->save(); $this->emit('success', 'Application settings updated!'); } catch (\Throwable $e) { diff --git a/app/Http/Livewire/Project/Service/Application.php b/app/Http/Livewire/Project/Service/Application.php index 0177de30c..bac6c6505 100644 --- a/app/Http/Livewire/Project/Service/Application.php +++ b/app/Http/Livewire/Project/Service/Application.php @@ -10,6 +10,7 @@ class Application extends Component public ServiceApplication $application; protected $rules = [ 'application.human_name' => 'nullable', + 'application.description' => 'nullable', 'application.fqdn' => 'nullable', ]; public function render() diff --git a/app/Http/Livewire/Project/Service/Database.php b/app/Http/Livewire/Project/Service/Database.php index 709eb2c35..50c9478d1 100644 --- a/app/Http/Livewire/Project/Service/Database.php +++ b/app/Http/Livewire/Project/Service/Database.php @@ -11,6 +11,7 @@ class Database extends Component public ServiceDatabase $database; protected $rules = [ 'database.human_name' => 'nullable', + 'database.description' => 'nullable', ]; public function render() { diff --git a/app/Http/Livewire/Project/Service/Index.php b/app/Http/Livewire/Project/Service/Index.php index 5b23ec33c..c59090fea 100644 --- a/app/Http/Livewire/Project/Service/Index.php +++ b/app/Http/Livewire/Project/Service/Index.php @@ -2,11 +2,7 @@ namespace App\Http\Livewire\Project\Service; -use App\Actions\Service\StartService; -use App\Actions\Service\StopService; -use App\Jobs\ContainerStatusJob; use App\Models\Service; -use Illuminate\Support\Collection; use Livewire\Component; class Index extends Component @@ -18,6 +14,8 @@ class Index extends Component protected $rules = [ 'service.docker_compose_raw' => 'required', 'service.docker_compose' => 'required', + 'service.name' => 'required', + 'service.description' => 'required', ]; public function mount() @@ -36,5 +34,13 @@ class Index extends Component $this->service->refresh(); $this->emit('refreshEnvs'); } + public function submit() { + try { + $this->validate(); + $this->service->save(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } } diff --git a/app/Http/Livewire/Project/Shared/Danger.php b/app/Http/Livewire/Project/Shared/Danger.php index 5fc363359..0de51939f 100644 --- a/app/Http/Livewire/Project/Shared/Danger.php +++ b/app/Http/Livewire/Project/Shared/Danger.php @@ -38,7 +38,7 @@ class Danger extends Component 'environment_name' => $this->parameters['environment_name'] ]); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } } diff --git a/app/Http/Livewire/Server/New/ByIp.php b/app/Http/Livewire/Server/New/ByIp.php index 7814aef8f..f5c8529de 100644 --- a/app/Http/Livewire/Server/New/ByIp.php +++ b/app/Http/Livewire/Server/New/ByIp.php @@ -79,7 +79,7 @@ class ByIp extends Component $server->settings->save(); return redirect()->route('server.show', $server->uuid); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } } diff --git a/app/Http/Livewire/Server/Proxy.php b/app/Http/Livewire/Server/Proxy.php index e4dd310eb..b218e6f98 100644 --- a/app/Http/Livewire/Server/Proxy.php +++ b/app/Http/Livewire/Server/Proxy.php @@ -54,7 +54,7 @@ class Proxy extends Component setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server); $this->emit('success', 'Proxy configuration saved.'); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } @@ -63,7 +63,7 @@ class Proxy extends Component try { $this->proxy_settings = CheckConfiguration::run($this->server, true); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } @@ -72,7 +72,7 @@ class Proxy extends Component try { $this->proxy_settings = CheckConfiguration::run($this->server); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } } diff --git a/app/Http/Livewire/Server/Proxy/Deploy.php b/app/Http/Livewire/Server/Proxy/Deploy.php index 790d9a251..d795f37b9 100644 --- a/app/Http/Livewire/Server/Proxy/Deploy.php +++ b/app/Http/Livewire/Server/Proxy/Deploy.php @@ -23,7 +23,7 @@ class Deploy extends Component $activity = StartProxy::run($this->server); $this->emit('newMonitorActivity', $activity->id); } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } diff --git a/app/Http/Livewire/Server/Proxy/Status.php b/app/Http/Livewire/Server/Proxy/Status.php index 061728049..9a88e23f2 100644 --- a/app/Http/Livewire/Server/Proxy/Status.php +++ b/app/Http/Livewire/Server/Proxy/Status.php @@ -23,7 +23,7 @@ class Status extends Component $this->emit('proxyStatusUpdated'); } } catch (\Throwable $e) { - return handleError($e); + return handleError($e, $this); } } public function getProxyStatusWithNoti() diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 7e59d99bd..ea8b43de2 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -96,7 +96,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if ($this->pull_request_id !== 0) { $this->preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id); if ($this->application->fqdn) { - $preview_fqdn = data_get($this->preview, 'fqdn'); + $preview_fqdn = getOnlyFqdn(data_get($this->preview, 'fqdn')); $template = $this->application->preview_url_template; $url = Url::fromString($this->application->fqdn); $host = $url->getHost(); @@ -625,75 +625,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted return $environment_variables->all(); } - private function set_labels_for_applications() - { - - $appId = $this->application->id; - if ($this->pull_request_id !== 0) { - $appId = $appId . '-pr-' . $this->pull_request_id; - } - $labels = []; - $labels[] = 'coolify.managed=true'; - $labels[] = 'coolify.version=' . config('version'); - $labels[] = 'coolify.applicationId=' . $appId; - $labels[] = 'coolify.type=application'; - $labels[] = 'coolify.name=' . $this->application->name; - if ($this->pull_request_id !== 0) { - $labels[] = 'coolify.pullRequestId=' . $this->pull_request_id; - } - if ($this->application->fqdn) { - if ($this->pull_request_id !== 0) { - $domains = Str::of(data_get($this->preview, 'fqdn'))->explode(','); - } else { - $domains = Str::of(data_get($this->application, 'fqdn'))->explode(','); - } - if ($this->application->destination->server->proxy->type === ProxyTypes::TRAEFIK_V2->value) { - $labels[] = 'traefik.enable=true'; - foreach ($domains as $domain) { - $url = Url::fromString($domain); - $host = $url->getHost(); - $path = $url->getPath(); - $schema = $url->getScheme(); - $slug = Str::slug($host . $path); - - $http_label = "{$this->container_name}-{$slug}-http"; - $https_label = "{$this->container_name}-{$slug}-https"; - - if ($schema === 'https') { - // Set labels for https - $labels[] = "traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"; - $labels[] = "traefik.http.routers.{$https_label}.entryPoints=https"; - $labels[] = "traefik.http.routers.{$https_label}.middlewares=gzip"; - if ($path !== '/') { - $labels[] = "traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix"; - $labels[] = "traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}"; - } - - $labels[] = "traefik.http.routers.{$https_label}.tls=true"; - $labels[] = "traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt"; - - // Set labels for http (redirect to https) - $labels[] = "traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"; - $labels[] = "traefik.http.routers.{$http_label}.entryPoints=http"; - if ($this->application->settings->is_force_https_enabled) { - $labels[] = "traefik.http.routers.{$http_label}.middlewares=redirect-to-https"; - } - } else { - // Set labels for http - $labels[] = "traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"; - $labels[] = "traefik.http.routers.{$http_label}.entryPoints=http"; - $labels[] = "traefik.http.routers.{$http_label}.middlewares=gzip"; - if ($path !== '/') { - $labels[] = "traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix"; - $labels[] = "traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}"; - } - } - } - } - } - return $labels; - } - private function generate_healthcheck_commands() { if ($this->application->dockerfile || $this->application->build_pack === 'dockerfile') { diff --git a/app/Models/Service.php b/app/Models/Service.php index 1ae97aa08..9390bc435 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -18,14 +18,14 @@ class Service extends BaseModel { static::deleted(function ($service) { $storagesToDelete = collect([]); - foreach($service->applications()->get() as $application) { + foreach ($service->applications()->get() as $application) { $storages = $application->persistentStorages()->get(); foreach ($storages as $storage) { $storagesToDelete->push($storage); } $application->persistentStorages()->delete(); } - foreach($service->databases()->get() as $database) { + foreach ($service->databases()->get() as $database) { $storages = $database->persistentStorages()->get(); foreach ($storages as $storage) { $storagesToDelete->push($storage); @@ -81,6 +81,7 @@ class Service extends BaseModel } public function parse(bool $isNew = false): Collection { + ray('parsing'); // ray()->clearAll(); if ($this->docker_compose_raw) { $yaml = Yaml::parse($this->docker_compose_raw); @@ -136,39 +137,43 @@ class Service extends BaseModel $savedService = $this->databases()->whereName($serviceName)->first(); } else { $savedService = $this->applications()->whereName($serviceName)->first(); - if (Str::of($serviceVariables)->contains('SERVICE_FQDN') || Str::of($serviceVariables)->contains('SERVICE_URL')) { - $defaultUsableFqdn = "http://$serviceName-{$this->uuid}.{$this->server->ip}.sslip.io"; - if (isDev()) { - $defaultUsableFqdn = "http://$serviceName-{$this->uuid}.127.0.0.1.sslip.io"; - } + if (data_get($savedService, 'fqdn')) { + $defaultUsableFqdn = data_get($savedService, 'fqdn', null); } else { - $defaultUsableFqdn = null; + if (Str::of($serviceVariables)->contains('SERVICE_FQDN') || Str::of($serviceVariables)->contains('SERVICE_URL')) { + $defaultUsableFqdn = "http://$serviceName-{$this->uuid}.{$this->server->ip}.sslip.io"; + if (isDev()) { + $defaultUsableFqdn = "http://$serviceName-{$this->uuid}.127.0.0.1.sslip.io"; + } + } } $savedService->fqdn = $defaultUsableFqdn; $savedService->save(); } } - $fqdn = data_get($savedService, 'fqdn'); + $fqdns = data_get($savedService, 'fqdn'); + if ($fqdns) { + $fqdns = collect(Str::of($fqdns)->explode(',')); + } + ray($fqdns); // Collect ports $servicePorts = collect(data_get($service, 'ports', [])); $ports->put($serviceName, $servicePorts); - if ($isNew) { - $ports = collect([]); - if ($servicePorts->count() > 0) { - foreach ($servicePorts as $sport) { - if (is_string($sport)) { - $ports->push($sport); - } - if (is_array($sport)) { - $target = data_get($sport, 'target'); - $published = data_get($sport, 'published'); - $ports->push("$target:$published"); - } + $collectedPorts = collect([]); + if ($servicePorts->count() > 0) { + foreach ($servicePorts as $sport) { + if (is_string($sport) || is_numeric($sport)) { + $collectedPorts->push($sport); + } + if (is_array($sport)) { + $target = data_get($sport, 'target'); + $published = data_get($sport, 'published'); + $collectedPorts->push("$target:$published"); } } - // $savedService->ports_exposes = $ports->implode(','); - // $savedService->save(); } + $savedService->ports = $collectedPorts->implode(','); + $savedService->save(); // Collect volumes $serviceVolumes = collect(data_get($service, 'volumes', [])); if ($serviceVolumes->count() > 0) { @@ -336,7 +341,14 @@ class Service extends BaseModel ]); } } else if ($variableName->startsWith('SERVICE_FQDN')) { - if ($fqdn) { + if ($fqdns) { + $number = Str::of($variableName)->after('SERVICE_FQDN')->afterLast('_')->value(); + if (is_numeric($number)) { + $number = (int) $number - 1; + } else { + $number = 0; + } + $fqdn = data_get($fqdns, $number); $environments = collect(data_get($service, 'environment')); $environments = $environments->map(function ($envValue) use ($value, $fqdn) { $envValue = Str::of($envValue)->replace($value, $fqdn); @@ -345,8 +357,9 @@ class Service extends BaseModel $service['environment'] = $environments->toArray(); } } else if ($variableName->startsWith('SERVICE_URL')) { - if ($fqdn) { - $url = Str::of($fqdn)->after('https://')->before('/'); + ray('url'); + if ($fqdns) { + $url = Str::of($fqdns)->after('https://')->before('/'); $environments = collect(data_get($service, 'environment')); $environments = $environments->map(function ($envValue) use ($value, $url) { $envValue = Str::of($envValue)->replace($value, $url); @@ -362,8 +375,8 @@ class Service extends BaseModel $labels = collect([]); $labels = $labels->merge(defaultLabels($this->id, $container_name, type: 'service')); if (!$isDatabase) { - if ($fqdn) { - $labels = $labels->merge(fqdnLabelsForTraefik($fqdn, $container_name, true)); + if ($fqdns) { + $labels = $labels->merge(fqdnLabelsForTraefik($fqdns, $container_name, true)); } } data_set($service, 'labels', $labels->toArray()); diff --git a/app/View/Components/Services/Links.php b/app/View/Components/Services/Links.php index e36d52d57..69fefa7a2 100644 --- a/app/View/Components/Services/Links.php +++ b/app/View/Components/Services/Links.php @@ -7,6 +7,7 @@ use Closure; use Illuminate\Contracts\View\View; use Illuminate\Support\Collection; use Illuminate\View\Component; +use Illuminate\Support\Str; class Links extends Component { @@ -15,7 +16,23 @@ class Links extends Component { $this->links = collect([]); $service->applications()->get()->map(function ($application) { - $this->links->push($application->fqdn); + if ($application->fqdn) { + $fqdns = collect(Str::of($application->fqdn)->explode(',')); + $fqdns->map(function ($fqdn) { + $this->links->push(getOnlyFqdn($fqdn)); + }); + } + if ($application->ports) { + $portsCollection = collect(Str::of($application->ports)->explode(',')); + $portsCollection->map(function ($port) { + if (Str::of($port)->contains(':')) { + $hostPort = Str::of($port)->before(':'); + } else { + $hostPort = $port; + } + $this->links->push(base_url(withPort:false) . ":{$hostPort}"); + }); + } }); } diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 90609af23..6d8e2e024 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -143,48 +143,60 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica } return $labels; } -function fqdnLabelsForTraefik($domain, $container_name, $is_force_https_enabled) +function fqdnLabelsForTraefik(Collection $domains, $container_name, $is_force_https_enabled) { $labels = collect([]); $labels->push('traefik.enable=true'); - $url = Url::fromString($domain); - $host = $url->getHost(); - $path = $url->getPath(); - $schema = $url->getScheme(); - $slug = Str::slug($host . $path); + foreach($domains as $domain) { + $url = Url::fromString($domain); + $host = $url->getHost(); + $path = $url->getPath(); + $schema = $url->getScheme(); + $port = $url->getPort(); + $slug = Str::slug($host . $path); - $http_label = "{$container_name}-{$slug}-http"; - $https_label = "{$container_name}-{$slug}-https"; + $http_label = "{$container_name}-{$slug}-http"; + $https_label = "{$container_name}-{$slug}-https"; - if ($schema === 'https') { - // Set labels for https - $labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); - $labels->push("traefik.http.routers.{$https_label}.entryPoints=https"); - $labels->push("traefik.http.routers.{$https_label}.middlewares=gzip"); - if ($path !== '/') { - $labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix"); - $labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}"); - } + if ($schema === 'https') { + // Set labels for https + $labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); + $labels->push("traefik.http.routers.{$https_label}.entryPoints=https"); + $labels->push("traefik.http.routers.{$https_label}.middlewares=gzip"); + if ($port) { + $labels->push("traefik.http.routers.{$https_label}.service={$https_label}"); + $labels->push("traefik.http.services.{$https_label}.loadbalancer.server.port=$port"); + } + if ($path !== '/') { + $labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix"); + $labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}"); + } - $labels->push("traefik.http.routers.{$https_label}.tls=true"); - $labels->push("traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt"); + $labels->push("traefik.http.routers.{$https_label}.tls=true"); + $labels->push("traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt"); - // Set labels for http (redirect to https) - $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); - $labels->push("traefik.http.routers.{$http_label}.entryPoints=http"); - if ($is_force_https_enabled) { - $labels->push("traefik.http.routers.{$http_label}.middlewares=redirect-to-https"); - } - } else { - // Set labels for http - $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); - $labels->push("traefik.http.routers.{$http_label}.entryPoints=http"); - $labels->push("traefik.http.routers.{$http_label}.middlewares=gzip"); - if ($path !== '/') { - $labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix"); - $labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}"); + // Set labels for http (redirect to https) + $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); + $labels->push("traefik.http.routers.{$http_label}.entryPoints=http"); + if ($is_force_https_enabled) { + $labels->push("traefik.http.routers.{$http_label}.middlewares=redirect-to-https"); + } + } else { + // Set labels for http + $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"); + $labels->push("traefik.http.routers.{$http_label}.entryPoints=http"); + $labels->push("traefik.http.routers.{$http_label}.middlewares=gzip"); + if ($port) { + $labels->push("traefik.http.routers.{$http_label}.service={$http_label}"); + $labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port"); + } + if ($path !== '/') { + $labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix"); + $labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}"); + } } } + return $labels; } function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array @@ -205,47 +217,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview $domains = Str::of(data_get($application, 'fqdn'))->explode(','); } if ($application->destination->server->proxy->type === ProxyTypes::TRAEFIK_V2->value) { - foreach ($domains as $domain) { - $labels = $labels->merge(fqdnLabelsForTraefik($domain, $container_name, $application->settings->is_force_https_enabled)); - // $url = Url::fromString($domain); - // $host = $url->getHost(); - // $path = $url->getPath(); - // $schema = $url->getScheme(); - // $slug = Str::slug($host . $path); - - // $http_label = "{$container_name}-{$slug}-http"; - // $https_label = "{$container_name}-{$slug}-https"; - - // if ($schema === 'https') { - // // Set labels for https - // $labels[] = "traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"; - // $labels[] = "traefik.http.routers.{$https_label}.entryPoints=https"; - // $labels[] = "traefik.http.routers.{$https_label}.middlewares=gzip"; - // if ($path !== '/') { - // $labels[] = "traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix"; - // $labels[] = "traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}"; - // } - - // $labels[] = "traefik.http.routers.{$https_label}.tls=true"; - // $labels[] = "traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt"; - - // // Set labels for http (redirect to https) - // $labels[] = "traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"; - // $labels[] = "traefik.http.routers.{$http_label}.entryPoints=http"; - // if ($application->settings->is_force_https_enabled) { - // $labels[] = "traefik.http.routers.{$http_label}.middlewares=redirect-to-https"; - // } - // } else { - // // Set labels for http - // $labels[] = "traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)"; - // $labels[] = "traefik.http.routers.{$http_label}.entryPoints=http"; - // $labels[] = "traefik.http.routers.{$http_label}.middlewares=gzip"; - // if ($path !== '/') { - // $labels[] = "traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix"; - // $labels[] = "traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}"; - // } - // } - } + $labels = $labels->merge(fqdnLabelsForTraefik($domains, $container_name, $application->settings->is_force_https_enabled)); } } return $labels->all(); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index e13a9ce3e..cb1a758a9 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -20,6 +20,7 @@ use Nubs\RandomNameGenerator\All; use Poliander\Cron\CronExpression; use Visus\Cuid2\Cuid2; use phpseclib3\Crypt\RSA; +use Spatie\Url\Url; function base_configuration_dir(): string { @@ -239,7 +240,12 @@ function base_ip(): string } return "localhost"; } - +function getOnlyFqdn(String $fqdn) { + $url = Url::fromString($fqdn); + $host = $url->getHost(); + $scheme = $url->getScheme(); + return "$scheme://$host"; +} /** * If fqdn is set, return it, otherwise return public ip. */ diff --git a/database/migrations/2023_09_20_082541_update_services_table.php b/database/migrations/2023_09_20_082541_update_services_table.php index 0abdafac3..959d5e6fd 100644 --- a/database/migrations/2023_09_20_082541_update_services_table.php +++ b/database/migrations/2023_09_20_082541_update_services_table.php @@ -12,6 +12,7 @@ return new class extends Migration public function up(): void { Schema::table('services', function (Blueprint $table) { + $table->longText('description')->nullable(); $table->longText('docker_compose_raw'); $table->longText('docker_compose')->nullable(); @@ -24,6 +25,7 @@ return new class extends Migration public function down(): void { Schema::table('services', function (Blueprint $table) { + $table->dropColumn('description'); $table->dropColumn('docker_compose_raw'); $table->dropColumn('docker_compose'); }); diff --git a/database/migrations/2023_09_20_082733_create_service_databases_table.php b/database/migrations/2023_09_20_082733_create_service_databases_table.php index 924c663ba..c76a7bb8f 100644 --- a/database/migrations/2023_09_20_082733_create_service_databases_table.php +++ b/database/migrations/2023_09_20_082733_create_service_databases_table.php @@ -16,6 +16,10 @@ return new class extends Migration $table->string('uuid')->unique(); $table->string('name'); $table->string('human_name')->nullable(); + $table->longText('description')->nullable(); + + $table->longText('ports')->nullable(); + $table->longText('exposes')->nullable(); $table->string('status')->default('exited'); diff --git a/database/migrations/2023_09_20_082737_create_service_applications_table.php b/database/migrations/2023_09_20_082737_create_service_applications_table.php index c4c363ed5..50a0d55b1 100644 --- a/database/migrations/2023_09_20_082737_create_service_applications_table.php +++ b/database/migrations/2023_09_20_082737_create_service_applications_table.php @@ -16,8 +16,11 @@ return new class extends Migration $table->string('uuid')->unique(); $table->string('name'); $table->string('human_name')->nullable(); + $table->longText('description')->nullable(); $table->string('fqdn')->unique()->nullable(); + $table->longText('ports')->nullable(); + $table->longText('exposes')->nullable(); $table->string('status')->default('exited'); diff --git a/resources/views/components/applications/links.blade.php b/resources/views/components/applications/links.blade.php index 0519d339e..c38ea185f 100644 --- a/resources/views/components/applications/links.blade.php +++ b/resources/views/components/applications/links.blade.php @@ -19,7 +19,7 @@ @foreach (Str::of(data_get($application, 'fqdn'))->explode(',') as $fqdn)
  • + target="_blank" href="{{ getOnlyFqdn($fqdn) }}"> @@ -28,7 +28,7 @@ - {{ $fqdn }} + {{ getOnlyFqdn($fqdn) }}
  • @endforeach @@ -38,7 +38,7 @@ @if (data_get($preview, 'fqdn'))
  • + target="_blank" href="{{ getOnlyFqdn(data_get($preview, 'fqdn')) }}"> diff --git a/resources/views/components/services/explanation.blade.php b/resources/views/components/services/explanation.blade.php deleted file mode 100644 index 7f8cdbc8c..000000000 --- a/resources/views/components/services/explanation.blade.php +++ /dev/null @@ -1,8 +0,0 @@ -
    -# You can use these variables in your Docker Compose file and Coolify will generate default values or replace them with the values you set on the UI forms.
    -#
    -# SERVICE_FQDN_*: FQDN - could be changable from the UI. (example: SERVICE_FQDN_GHOST)
    -# SERVICE_URL_*: URL parsed from FQDN - could be changable from the UI. (example: SERVICE_URL_GHOST)
    -# SERVICE_USER_*: Generated user, not encrypted in database (example: SERVICE_USER_MYSQL)
    -# SERVICE_PASSWORD_*: Generated password, encrypted in database (example: SERVICE_PASSWORD_MYSQL)
    -
    diff --git a/resources/views/components/services/navbar.blade.php b/resources/views/components/services/navbar.blade.php index 98a4a2334..779e8ccfe 100644 --- a/resources/views/components/services/navbar.blade.php +++ b/resources/views/components/services/navbar.blade.php @@ -1,8 +1,4 @@
    +
    + + @if ($wildcard_domain) + @if ($global_wildcard_domain) + Set Global Wildcard + + @endif + @if ($server_wildcard_domain) + Set Server Wildcard + + @endif + @endif +
    @if ($application->settings->is_static) @@ -46,7 +60,7 @@ @else + helper="A comma separated list of ports your application uses. The first port will be used as default healthcheck endpoint. Be sure to set this correctly." /> @endif diff --git a/resources/views/livewire/project/new/docker-compose.blade.php b/resources/views/livewire/project/new/docker-compose.blade.php index c9823c438..1307f40de 100644 --- a/resources/views/livewire/project/new/docker-compose.blade.php +++ b/resources/views/livewire/project/new/docker-compose.blade.php @@ -6,8 +6,15 @@

    Docker Compose

    Save - - Compose File Service Stack + Compose File Environment @@ -17,6 +17,17 @@ -
    - +
    - - +
    diff --git a/resources/views/livewire/project/service/show.blade.php b/resources/views/livewire/project/service/show.blade.php index 7793777c4..eba246615 100644 --- a/resources/views/livewire/project/service/show.blade.php +++ b/resources/views/livewire/project/service/show.blade.php @@ -2,6 +2,10 @@
    diff --git a/resources/views/project/application/configuration.blade.php b/resources/views/project/application/configuration.blade.php index 3d43a349c..b077eaa27 100644 --- a/resources/views/project/application/configuration.blade.php +++ b/resources/views/project/application/configuration.blade.php @@ -13,9 +13,9 @@ Source @endif - Destination + Server Storages @@ -49,7 +49,7 @@
    @endif -
    +
    diff --git a/resources/views/project/database/backups/all.blade.php b/resources/views/project/database/backups/all.blade.php index 6f5dcc54e..80a2fd816 100644 --- a/resources/views/project/database/backups/all.blade.php +++ b/resources/views/project/database/backups/all.blade.php @@ -3,7 +3,7 @@ - + diff --git a/resources/views/project/database/backups/executions.blade.php b/resources/views/project/database/backups/executions.blade.php index 8fdd877de..afcd0c061 100644 --- a/resources/views/project/database/backups/executions.blade.php +++ b/resources/views/project/database/backups/executions.blade.php @@ -3,7 +3,7 @@ - + diff --git a/resources/views/project/database/configuration.blade.php b/resources/views/project/database/configuration.blade.php index fff07cac8..5c16a0050 100644 --- a/resources/views/project/database/configuration.blade.php +++ b/resources/views/project/database/configuration.blade.php @@ -3,7 +3,7 @@ - + @@ -19,9 +19,9 @@ @click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'" href="#">Environment Variables - Destination + Server Storages @@ -43,7 +43,7 @@
    -
    +