feat: experimental caddy support
This commit is contained in:
		@@ -11,7 +11,12 @@ class CheckConfiguration
 | 
				
			|||||||
    use AsAction;
 | 
					    use AsAction;
 | 
				
			||||||
    public function handle(Server $server, bool $reset = false)
 | 
					    public function handle(Server $server, bool $reset = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $proxy_path = get_proxy_path();
 | 
					        $proxyType = $server->proxyType();
 | 
				
			||||||
 | 
					        if ($proxyType === 'NONE') {
 | 
				
			||||||
 | 
					            return 'OK';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $proxy_path = $server->proxyPath();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $proxy_configuration = instant_remote_process([
 | 
					        $proxy_configuration = instant_remote_process([
 | 
				
			||||||
            "mkdir -p $proxy_path",
 | 
					            "mkdir -p $proxy_path",
 | 
				
			||||||
            "cat $proxy_path/docker-compose.yml",
 | 
					            "cat $proxy_path/docker-compose.yml",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,9 @@ class CheckProxy
 | 
				
			|||||||
    use AsAction;
 | 
					    use AsAction;
 | 
				
			||||||
    public function handle(Server $server, $fromUI = false)
 | 
					    public function handle(Server $server, $fromUI = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        if ($server->proxyType() === 'NONE') {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (!$server->isProxyShouldRun()) {
 | 
					        if (!$server->isProxyShouldRun()) {
 | 
				
			||||||
            if ($fromUI) {
 | 
					            if ($fromUI) {
 | 
				
			||||||
                throw new \Exception("Proxy should not run. You selected the Custom Proxy.");
 | 
					                throw new \Exception("Proxy should not run. You selected the Custom Proxy.");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ class SaveConfiguration
 | 
				
			|||||||
        if (is_null($proxy_settings)) {
 | 
					        if (is_null($proxy_settings)) {
 | 
				
			||||||
            $proxy_settings = CheckConfiguration::run($server, true);
 | 
					            $proxy_settings = CheckConfiguration::run($server, true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $proxy_path = get_proxy_path();
 | 
					        $proxy_path = $server->proxyPath();
 | 
				
			||||||
        $docker_compose_yml_base64 = base64_encode($proxy_settings);
 | 
					        $docker_compose_yml_base64 = base64_encode($proxy_settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
 | 
					        $server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,11 +15,11 @@ class StartProxy
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $proxyType = $server->proxyType();
 | 
					            $proxyType = $server->proxyType();
 | 
				
			||||||
            if ($proxyType === 'NONE') {
 | 
					            if (is_null($proxyType) || $proxyType === 'NONE') {
 | 
				
			||||||
                return 'OK';
 | 
					                return 'OK';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            $commands = collect([]);
 | 
					            $commands = collect([]);
 | 
				
			||||||
            $proxy_path = get_proxy_path();
 | 
					            $proxy_path = $server->proxyPath();
 | 
				
			||||||
            $configuration = CheckConfiguration::run($server);
 | 
					            $configuration = CheckConfiguration::run($server);
 | 
				
			||||||
            if (!$configuration) {
 | 
					            if (!$configuration) {
 | 
				
			||||||
                throw new \Exception("Configuration is not synced");
 | 
					                throw new \Exception("Configuration is not synced");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -126,6 +126,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    public function getProxyType()
 | 
					    public function getProxyType()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // Set Default Proxy Type
 | 
				
			||||||
        $this->selectProxy(ProxyTypes::TRAEFIK_V2->value);
 | 
					        $this->selectProxy(ProxyTypes::TRAEFIK_V2->value);
 | 
				
			||||||
        // $proxyTypeSet = $this->createdServer->proxy->type;
 | 
					        // $proxyTypeSet = $this->createdServer->proxy->type;
 | 
				
			||||||
        // if (!$proxyTypeSet) {
 | 
					        // if (!$proxyTypeSet) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,7 +124,7 @@ class General extends Component
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        $this->isConfigurationChanged = $this->application->isConfigurationChanged();
 | 
					        $this->isConfigurationChanged = $this->application->isConfigurationChanged();
 | 
				
			||||||
        $this->customLabels = $this->application->parseContainerLabels();
 | 
					        $this->customLabels = $this->application->parseContainerLabels();
 | 
				
			||||||
        if (!$this->customLabels && $this->application->destination->server->proxyType() === 'TRAEFIK_V2') {
 | 
					        if (!$this->customLabels && $this->application->destination->server->proxyType() !== 'NONE') {
 | 
				
			||||||
            $this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
 | 
					            $this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
 | 
				
			||||||
            $this->application->custom_labels = base64_encode($this->customLabels);
 | 
					            $this->application->custom_labels = base64_encode($this->customLabels);
 | 
				
			||||||
            $this->application->save();
 | 
					            $this->application->save();
 | 
				
			||||||
@@ -224,7 +224,7 @@ class General extends Component
 | 
				
			|||||||
    public function submit($showToaster = true)
 | 
					    public function submit($showToaster = true)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            if (!$this->customLabels && $this->application->destination->server->proxyType() === 'TRAEFIK_V2') {
 | 
					            if (!$this->customLabels && $this->application->destination->server->proxyType() !== 'NONE') {
 | 
				
			||||||
                $this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
 | 
					                $this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
 | 
				
			||||||
                $this->application->custom_labels = base64_encode($this->customLabels);
 | 
					                $this->application->custom_labels = base64_encode($this->customLabels);
 | 
				
			||||||
                $this->application->save();
 | 
					                $this->application->save();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ class ResourceOperations extends Component
 | 
				
			|||||||
                'destination_id' => $new_destination->id,
 | 
					                'destination_id' => $new_destination->id,
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
            $new_resource->save();
 | 
					            $new_resource->save();
 | 
				
			||||||
            if ($new_resource->destination->server->proxyType() === 'TRAEFIK_V2') {
 | 
					            if ($new_resource->destination->server->proxyType() !== 'NONE') {
 | 
				
			||||||
                $customLabels = str(implode("|", generateLabelsApplication($new_resource)))->replace("|", "\n");
 | 
					                $customLabels = str(implode("|", generateLabelsApplication($new_resource)))->replace("|", "\n");
 | 
				
			||||||
                $new_resource->custom_labels = base64_encode($customLabels);
 | 
					                $new_resource->custom_labels = base64_encode($customLabels);
 | 
				
			||||||
                $new_resource->save();
 | 
					                $new_resource->save();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,6 +89,7 @@ class ByIp extends Component
 | 
				
			|||||||
                'team_id' => currentTeam()->id,
 | 
					                'team_id' => currentTeam()->id,
 | 
				
			||||||
                'private_key_id' => $this->private_key_id,
 | 
					                'private_key_id' => $this->private_key_id,
 | 
				
			||||||
                'proxy' => [
 | 
					                'proxy' => [
 | 
				
			||||||
 | 
					                    // set default proxy type to traefik v2
 | 
				
			||||||
                    "type" => ProxyTypes::TRAEFIK_V2->value,
 | 
					                    "type" => ProxyTypes::TRAEFIK_V2->value,
 | 
				
			||||||
                    "status" => ProxyStatus::EXITED->value,
 | 
					                    "status" => ProxyStatus::EXITED->value,
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ class DynamicConfigurationNavbar extends Component
 | 
				
			|||||||
    public function delete(string $fileName)
 | 
					    public function delete(string $fileName)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $server = Server::ownedByCurrentTeam()->whereId($this->server_id)->first();
 | 
					        $server = Server::ownedByCurrentTeam()->whereId($this->server_id)->first();
 | 
				
			||||||
        $proxy_path = get_proxy_path();
 | 
					        $proxy_path = $server->proxyPath();
 | 
				
			||||||
        $file = str_replace('|', '.', $fileName);
 | 
					        $file = str_replace('|', '.', $fileName);
 | 
				
			||||||
        instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $server);
 | 
					        instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $server);
 | 
				
			||||||
        $this->dispatch('success', 'File deleted.');
 | 
					        $this->dispatch('success', 'File deleted.');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ class DynamicConfigurations extends Component
 | 
				
			|||||||
    ];
 | 
					    ];
 | 
				
			||||||
    public function loadDynamicConfigurations()
 | 
					    public function loadDynamicConfigurations()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $proxy_path = get_proxy_path();
 | 
					        $proxy_path = $this->server->proxyPath();
 | 
				
			||||||
        $files = instant_remote_process(["mkdir -p $proxy_path/dynamic && ls -1 {$proxy_path}/dynamic"], $this->server);
 | 
					        $files = instant_remote_process(["mkdir -p $proxy_path/dynamic && ls -1 {$proxy_path}/dynamic"], $this->server);
 | 
				
			||||||
        $files = collect(explode("\n", $files))->filter(fn ($file) => !empty($file));
 | 
					        $files = collect(explode("\n", $files))->filter(fn ($file) => !empty($file));
 | 
				
			||||||
        $files = $files->map(fn ($file) => trim($file));
 | 
					        $files = $files->map(fn ($file) => trim($file));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ class NewDynamicConfiguration extends Component
 | 
				
			|||||||
                $this->dispatch('error', 'File name is reserved.');
 | 
					                $this->dispatch('error', 'File name is reserved.');
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            $proxy_path = get_proxy_path();
 | 
					            $proxy_path = $this->proxyPath();
 | 
				
			||||||
            $file = "{$proxy_path}/dynamic/{$this->fileName}";
 | 
					            $file = "{$proxy_path}/dynamic/{$this->fileName}";
 | 
				
			||||||
            if ($this->newFile) {
 | 
					            if ($this->newFile) {
 | 
				
			||||||
                $exists = instant_remote_process(["test -f $file && echo 1 || echo 0"], $this->server);
 | 
					                $exists = instant_remote_process(["test -f $file && echo 1 || echo 0"], $this->server);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -118,17 +118,30 @@ class Server extends BaseModel
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    public function proxyPath() {
 | 
				
			||||||
 | 
					        $base_path = config('coolify.base_config_path');
 | 
				
			||||||
 | 
					        $proxyType = $this->proxyType();
 | 
				
			||||||
 | 
					        $proxy_path = "$base_path/proxy";
 | 
				
			||||||
 | 
					        if ($proxyType === ProxyTypes::TRAEFIK_V2->value) {
 | 
				
			||||||
 | 
					            $proxy_path = $proxy_path;
 | 
				
			||||||
 | 
					        } else if ($proxyType === ProxyTypes::CADDY->value) {
 | 
				
			||||||
 | 
					            $proxy_path = $proxy_path . '/caddy';
 | 
				
			||||||
 | 
					        } else if ($proxyType === ProxyTypes::NGINX->value) {
 | 
				
			||||||
 | 
					            $proxy_path = $proxy_path . '/nginx';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $proxy_path;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    public function proxyType()
 | 
					    public function proxyType()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $proxyType = $this->proxy->get('type');
 | 
					        $proxyType = $this->proxy->get('type');
 | 
				
			||||||
        if ($proxyType === ProxyTypes::NONE->value) {
 | 
					        if ($proxyType === ProxyTypes::NONE->value) {
 | 
				
			||||||
            return $proxyType;
 | 
					            return $proxyType;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (is_null($proxyType)) {
 | 
					        // if (is_null($proxyType)) {
 | 
				
			||||||
            $this->proxy->type = ProxyTypes::TRAEFIK_V2->value;
 | 
					        //     $this->proxy->type = ProxyTypes::TRAEFIK_V2->value;
 | 
				
			||||||
            $this->proxy->status = ProxyStatus::EXITED->value;
 | 
					        //     $this->proxy->status = ProxyStatus::EXITED->value;
 | 
				
			||||||
            $this->save();
 | 
					        //     $this->save();
 | 
				
			||||||
        }
 | 
					        // }
 | 
				
			||||||
        return $this->proxy->get('type');
 | 
					        return $this->proxy->get('type');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public function scopeWithProxy(): Builder
 | 
					    public function scopeWithProxy(): Builder
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Enums\ProxyTypes;
 | 
				
			||||||
use App\Models\Application;
 | 
					use App\Models\Application;
 | 
				
			||||||
use App\Models\ApplicationPreview;
 | 
					use App\Models\ApplicationPreview;
 | 
				
			||||||
use App\Models\Server;
 | 
					use App\Models\Server;
 | 
				
			||||||
@@ -215,6 +216,46 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return $payload;
 | 
					    return $payload;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    $labels = collect([]);
 | 
				
			||||||
 | 
					    foreach ($domains as $loop => $domain) {
 | 
				
			||||||
 | 
					        $loop = $loop;
 | 
				
			||||||
 | 
					        $url = Url::fromString($domain);
 | 
				
			||||||
 | 
					        $host = $url->getHost();
 | 
				
			||||||
 | 
					        $path = $url->getPath();
 | 
				
			||||||
 | 
					        // $stripped_path = str($path)->replaceEnd('/', '');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $schema = $url->getScheme();
 | 
				
			||||||
 | 
					        $port = $url->getPort();
 | 
				
			||||||
 | 
					        if (is_null($port) && !is_null($onlyPort)) {
 | 
				
			||||||
 | 
					            $port = $onlyPort;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $labels->push("caddy_{$loop}={$schema}://{$host}");
 | 
				
			||||||
 | 
					        $labels->push("caddy_{$loop}.header=-Server");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($serviceLabels) {
 | 
				
			||||||
 | 
					            $labels->push("caddy_ingress_network={$uuid}");
 | 
				
			||||||
 | 
					            $labels->push("caddy_{$loop}.reverse_proxy={{upstreams}}");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $labels->push("caddy_ingress_network={$network}");
 | 
				
			||||||
 | 
					            if ($port) {
 | 
				
			||||||
 | 
					                $labels->push("caddy_{$loop}.handle_path.{$loop}_reverse_proxy={{upstreams $port}}");
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $labels->push("caddy_{$loop}.handle_path.{$loop}_reverse_proxy={{upstreams}}");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $labels->push("caddy_{$loop}.handle_path={$path}*");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($is_gzip_enabled) {
 | 
				
			||||||
 | 
					            $labels->push("caddy_{$loop}.encode=zstd gzip");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (isDev()) {
 | 
				
			||||||
 | 
					            // $labels->push("caddy_{$loop}.tls=internal");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return $labels->sort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null)
 | 
					function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    $labels = collect([]);
 | 
					    $labels = collect([]);
 | 
				
			||||||
@@ -395,7 +436,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            $domains = Str::of(data_get($application, 'fqdn'))->explode(',');
 | 
					            $domains = Str::of(data_get($application, 'fqdn'))->explode(',');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // Add Traefik labels no matter which proxy is selected
 | 
					        // Add Traefik labels
 | 
				
			||||||
        $labels = $labels->merge(fqdnLabelsForTraefik(
 | 
					        $labels = $labels->merge(fqdnLabelsForTraefik(
 | 
				
			||||||
            uuid: $appUuid,
 | 
					            uuid: $appUuid,
 | 
				
			||||||
            domains: $domains,
 | 
					            domains: $domains,
 | 
				
			||||||
@@ -404,6 +445,16 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
 | 
				
			|||||||
            is_gzip_enabled: $application->isGzipEnabled(),
 | 
					            is_gzip_enabled: $application->isGzipEnabled(),
 | 
				
			||||||
            is_stripprefix_enabled: $application->isStripprefixEnabled()
 | 
					            is_stripprefix_enabled: $application->isStripprefixEnabled()
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
 | 
					        // Add Caddy labels
 | 
				
			||||||
 | 
					        $labels = $labels->merge(fqdnLabelsForCaddy(
 | 
				
			||||||
 | 
					            network: $application->destination->network,
 | 
				
			||||||
 | 
					            uuid: $appUuid,
 | 
				
			||||||
 | 
					            domains: $domains,
 | 
				
			||||||
 | 
					            onlyPort: $onlyPort,
 | 
				
			||||||
 | 
					            is_force_https_enabled: $application->isForceHttpsEnabled(),
 | 
				
			||||||
 | 
					            is_gzip_enabled: $application->isGzipEnabled(),
 | 
				
			||||||
 | 
					            is_stripprefix_enabled: $application->isStripprefixEnabled()
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return $labels->all();
 | 
					    return $labels->all();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,7 @@ use App\Models\Server;
 | 
				
			|||||||
use Spatie\Url\Url;
 | 
					use Spatie\Url\Url;
 | 
				
			||||||
use Symfony\Component\Yaml\Yaml;
 | 
					use Symfony\Component\Yaml\Yaml;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function get_proxy_path()
 | 
					
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    $base_path = config('coolify.base_config_path');
 | 
					 | 
				
			||||||
    $proxy_path = "$base_path/proxy";
 | 
					 | 
				
			||||||
    return $proxy_path;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
function connectProxyToNetworks(Server $server)
 | 
					function connectProxyToNetworks(Server $server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if ($server->isSwarm()) {
 | 
					    if ($server->isSwarm()) {
 | 
				
			||||||
@@ -75,7 +70,9 @@ function connectProxyToNetworks(Server $server)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
function generate_default_proxy_configuration(Server $server)
 | 
					function generate_default_proxy_configuration(Server $server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    $proxy_path = get_proxy_path();
 | 
					    $proxy_path = $server->proxyPath();
 | 
				
			||||||
 | 
					    $proxy_type = $server->proxyType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ($server->isSwarm()) {
 | 
					    if ($server->isSwarm()) {
 | 
				
			||||||
        $networks = collect($server->swarmDockers)->map(function ($docker) {
 | 
					        $networks = collect($server->swarmDockers)->map(function ($docker) {
 | 
				
			||||||
            return $docker['network'];
 | 
					            return $docker['network'];
 | 
				
			||||||
@@ -98,6 +95,7 @@ function generate_default_proxy_configuration(Server $server)
 | 
				
			|||||||
            "external" => true,
 | 
					            "external" => true,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    if ($proxy_type === 'TRAEFIK_V2') {
 | 
				
			||||||
        $labels = [
 | 
					        $labels = [
 | 
				
			||||||
            "traefik.enable=true",
 | 
					            "traefik.enable=true",
 | 
				
			||||||
            "traefik.http.routers.traefik.entrypoints=http",
 | 
					            "traefik.http.routers.traefik.entrypoints=http",
 | 
				
			||||||
@@ -176,15 +174,50 @@ function generate_default_proxy_configuration(Server $server)
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            $config['services']['traefik']['command'][] = "--providers.docker=true";
 | 
					            $config['services']['traefik']['command'][] = "--providers.docker=true";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    } else if ($proxy_type === 'CADDY') {
 | 
				
			||||||
 | 
					        $config = [
 | 
				
			||||||
 | 
					            "version" => "3.8",
 | 
				
			||||||
 | 
					            "networks" => $array_of_networks->toArray(),
 | 
				
			||||||
 | 
					            "services" => [
 | 
				
			||||||
 | 
					                "caddy" => [
 | 
				
			||||||
 | 
					                    "container_name" => "coolify-proxy",
 | 
				
			||||||
 | 
					                    "image" => "lucaslorentz/caddy-docker-proxy:2.8-alpine",
 | 
				
			||||||
 | 
					                    "restart" => RESTART_MODE,
 | 
				
			||||||
 | 
					                    "extra_hosts" => [
 | 
				
			||||||
 | 
					                        "host.docker.internal:host-gateway",
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    "networks" => $networks->toArray(),
 | 
				
			||||||
 | 
					                    "ports" => [
 | 
				
			||||||
 | 
					                        "80:80",
 | 
				
			||||||
 | 
					                        "443:443",
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    // "healthcheck" => [
 | 
				
			||||||
 | 
					                    //     "test" => "wget -qO- http://localhost:80|| exit 1",
 | 
				
			||||||
 | 
					                    //     "interval" => "4s",
 | 
				
			||||||
 | 
					                    //     "timeout" => "2s",
 | 
				
			||||||
 | 
					                    //     "retries" => 5,
 | 
				
			||||||
 | 
					                    // ],
 | 
				
			||||||
 | 
					                    "volumes" => [
 | 
				
			||||||
 | 
					                        "/var/run/docker.sock:/var/run/docker.sock:ro",
 | 
				
			||||||
 | 
					                        "{$proxy_path}/config:/config",
 | 
				
			||||||
 | 
					                        "{$proxy_path}/data:/data",
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $config = Yaml::dump($config, 12, 2);
 | 
					    $config = Yaml::dump($config, 12, 2);
 | 
				
			||||||
    SaveConfiguration::run($server, $config);
 | 
					    SaveConfiguration::run($server, $config);
 | 
				
			||||||
    return $config;
 | 
					    return $config;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
function setup_dynamic_configuration()
 | 
					function setup_dynamic_configuration()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    $dynamic_config_path = get_proxy_path() . "/dynamic";
 | 
					 | 
				
			||||||
    $settings = InstanceSettings::get();
 | 
					    $settings = InstanceSettings::get();
 | 
				
			||||||
    $server = Server::find(0);
 | 
					    $server = Server::find(0);
 | 
				
			||||||
 | 
					    $dynamic_config_path = $server->proxyPath() . "/dynamic";
 | 
				
			||||||
    if ($server) {
 | 
					    if ($server) {
 | 
				
			||||||
        $file = "$dynamic_config_path/coolify.yaml";
 | 
					        $file = "$dynamic_config_path/coolify.yaml";
 | 
				
			||||||
        if (empty($settings->fqdn)) {
 | 
					        if (empty($settings->fqdn)) {
 | 
				
			||||||
@@ -308,7 +341,7 @@ function setup_dynamic_configuration()
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
function setup_default_redirect_404(string|null $redirect_url, Server $server)
 | 
					function setup_default_redirect_404(string|null $redirect_url, Server $server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    $traefik_dynamic_conf_path = get_proxy_path() . "/dynamic";
 | 
					    $traefik_dynamic_conf_path = $server->proxyPath() . "/dynamic";
 | 
				
			||||||
    $traefik_default_redirect_file = "$traefik_dynamic_conf_path/default_redirect_404.yaml";
 | 
					    $traefik_default_redirect_file = "$traefik_dynamic_conf_path/default_redirect_404.yaml";
 | 
				
			||||||
    if (empty($redirect_url)) {
 | 
					    if (empty($redirect_url)) {
 | 
				
			||||||
        instant_remote_process([
 | 
					        instant_remote_process([
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1056,6 +1056,16 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
 | 
				
			|||||||
                            is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
 | 
					                            is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
 | 
				
			||||||
                            service_name: $serviceName
 | 
					                            service_name: $serviceName
 | 
				
			||||||
                        ));
 | 
					                        ));
 | 
				
			||||||
 | 
					                        $serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
 | 
				
			||||||
 | 
					                            network: $resource->destination->network,
 | 
				
			||||||
 | 
					                            uuid: $resource->uuid,
 | 
				
			||||||
 | 
					                            domains: $fqdns,
 | 
				
			||||||
 | 
					                            is_force_https_enabled: true,
 | 
				
			||||||
 | 
					                            serviceLabels: $serviceLabels,
 | 
				
			||||||
 | 
					                            is_gzip_enabled: $savedService->isGzipEnabled(),
 | 
				
			||||||
 | 
					                            is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
 | 
				
			||||||
 | 
					                            service_name: $serviceName
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if ($resource->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) {
 | 
					                if ($resource->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) {
 | 
				
			||||||
@@ -1495,7 +1505,17 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
 | 
				
			|||||||
                                return $preview_fqdn;
 | 
					                                return $preview_fqdn;
 | 
				
			||||||
                            });
 | 
					                            });
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($uuid, $fqdns, serviceLabels: $serviceLabels));
 | 
					                        $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik(
 | 
				
			||||||
 | 
					                            uuid: $uuid,
 | 
				
			||||||
 | 
					                            domains: $fqdns,
 | 
				
			||||||
 | 
					                            serviceLabels: $serviceLabels
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
 | 
					                        $serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
 | 
				
			||||||
 | 
					                            network: $resource->destination->network,
 | 
				
			||||||
 | 
					                            uuid: $uuid,
 | 
				
			||||||
 | 
					                            domains: $fqdns,
 | 
				
			||||||
 | 
					                            serviceLabels: $serviceLabels
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
return [
 | 
					return [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
 | 
					    // @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
 | 
				
			||||||
    'dsn' => 'https://1bbc8f762199a52aee39196adb3e8d1a@o1082494.ingest.sentry.io/4505347448045568',
 | 
					    'dsn' => 'https://f0b0e6be13926d4ac68d68d51d38db8f@o1082494.ingest.us.sentry.io/4505347448045568',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The release version of your application
 | 
					    // The release version of your application
 | 
				
			||||||
    // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
 | 
					    // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,11 +4,13 @@
 | 
				
			|||||||
            href="{{ route('server.proxy', $parameters) }}">
 | 
					            href="{{ route('server.proxy', $parameters) }}">
 | 
				
			||||||
            <button>Configuration</button>
 | 
					            <button>Configuration</button>
 | 
				
			||||||
        </a>
 | 
					        </a>
 | 
				
			||||||
        @if (data_get($server, 'proxy.type') !== 'NONE')
 | 
					        @if ($server->proxyType() !== 'NONE')
 | 
				
			||||||
 | 
					            @if ($server->proxyType() === 'TRAEFIK_V2')
 | 
				
			||||||
                <a class="{{ request()->routeIs('server.proxy.dynamic-confs') ? 'text-white' : '' }}"
 | 
					                <a class="{{ request()->routeIs('server.proxy.dynamic-confs') ? 'text-white' : '' }}"
 | 
				
			||||||
                    href="{{ route('server.proxy.dynamic-confs', $parameters) }}">
 | 
					                    href="{{ route('server.proxy.dynamic-confs', $parameters) }}">
 | 
				
			||||||
                    <button>Dynamic Configurations</button>
 | 
					                    <button>Dynamic Configurations</button>
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
 | 
					            @endif
 | 
				
			||||||
            <a class="{{ request()->routeIs('server.proxy.logs') ? 'text-white' : '' }}"
 | 
					            <a class="{{ request()->routeIs('server.proxy.logs') ? 'text-white' : '' }}"
 | 
				
			||||||
                href="{{ route('server.proxy.logs', $parameters) }}">
 | 
					                href="{{ route('server.proxy.logs', $parameters) }}">
 | 
				
			||||||
                <button>Logs</button>
 | 
					                <button>Logs</button>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,24 @@
 | 
				
			|||||||
<div>
 | 
					<div>
 | 
				
			||||||
    @if (data_get($server, 'proxy.type'))
 | 
					    @if (data_get($server, 'proxy.type'))
 | 
				
			||||||
        <div x-init="$wire.loadProxyConfiguration">
 | 
					        <div x-init="$wire.loadProxyConfiguration">
 | 
				
			||||||
            @if ($selectedProxy === 'TRAEFIK_V2')
 | 
					            @if ($selectedProxy !== 'NONE')
 | 
				
			||||||
                <form wire:submit='submit'>
 | 
					                <form wire:submit='submit'>
 | 
				
			||||||
                    <div class="flex items-center gap-2">
 | 
					                    <div class="flex items-center gap-2">
 | 
				
			||||||
                        <h2>Configuration</h2>
 | 
					                        <h2>Configuration</h2>
 | 
				
			||||||
                        <x-forms.button type="submit">Save</x-forms.button>
 | 
					 | 
				
			||||||
                        @if ($server->proxy->status === 'exited')
 | 
					                        @if ($server->proxy->status === 'exited')
 | 
				
			||||||
                            <x-forms.button wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
 | 
					                            <x-forms.button wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
 | 
				
			||||||
 | 
					                        @else
 | 
				
			||||||
 | 
					                            <x-forms.button disabled wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
 | 
					                        <x-forms.button type="submit">Save</x-forms.button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                    <div class="pt-3 pb-4 ">Traefik v2</div>
 | 
					                    <div class="pb-4 ">Before switching proxies, please read <a>this</a>.</div>
 | 
				
			||||||
 | 
					                    @if ($server->proxyType() === 'TRAEFIK_V2')
 | 
				
			||||||
 | 
					                        <div class="pb-4">Traefik v2</div>
 | 
				
			||||||
 | 
					                    @elseif ($server->proxyType() === 'CADDY')
 | 
				
			||||||
 | 
					                        <div class="pb-4 ">Caddy</div>
 | 
				
			||||||
 | 
					                    @endif
 | 
				
			||||||
                    @if (
 | 
					                    @if (
 | 
				
			||||||
                        $server->proxy->last_applied_settings &&
 | 
					                        $server->proxy->last_applied_settings &&
 | 
				
			||||||
                            $server->proxy->last_saved_settings !== $server->proxy->last_applied_settings)
 | 
					                            $server->proxy->last_saved_settings !== $server->proxy->last_applied_settings)
 | 
				
			||||||
@@ -18,15 +26,18 @@
 | 
				
			|||||||
                            configurations.
 | 
					                            configurations.
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    @endif
 | 
					                    @endif
 | 
				
			||||||
                    <x-forms.input placeholder="https://app.coolify.io" id="redirect_url" label="Default Redirect 404"
 | 
					                    @if ($server->proxyType() === 'TRAEFIK_V2')
 | 
				
			||||||
 | 
					                        <x-forms.input placeholder="https://app.coolify.io" id="redirect_url"
 | 
				
			||||||
 | 
					                            label="Default Redirect 404"
 | 
				
			||||||
                            helper="All urls that has no service available will be redirected to this domain." />
 | 
					                            helper="All urls that has no service available will be redirected to this domain." />
 | 
				
			||||||
 | 
					                    @endif
 | 
				
			||||||
                    <div wire:loading wire:target="loadProxyConfiguration" class="pt-4">
 | 
					                    <div wire:loading wire:target="loadProxyConfiguration" class="pt-4">
 | 
				
			||||||
                        <x-loading text="Loading proxy configuration..." />
 | 
					                        <x-loading text="Loading proxy configuration..." />
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                    <div wire:loading.remove wire:target="loadProxyConfiguration">
 | 
					                    <div wire:loading.remove wire:target="loadProxyConfiguration">
 | 
				
			||||||
                        @if ($proxy_settings)
 | 
					                        @if ($proxy_settings)
 | 
				
			||||||
                            <div class="flex flex-col gap-2 pt-4">
 | 
					                            <div class="flex flex-col gap-2 pt-4">
 | 
				
			||||||
                                <x-forms.textarea label="Configuration file: traefik.conf" name="proxy_settings"
 | 
					                                <x-forms.textarea label="Configuration file" name="proxy_settings"
 | 
				
			||||||
                                    wire:model="proxy_settings" rows="30" />
 | 
					                                    wire:model="proxy_settings" rows="30" />
 | 
				
			||||||
                                <x-forms.button wire:click.prevent="reset_proxy_configuration">
 | 
					                                <x-forms.button wire:click.prevent="reset_proxy_configuration">
 | 
				
			||||||
                                    Reset configuration to default
 | 
					                                    Reset configuration to default
 | 
				
			||||||
@@ -40,7 +51,7 @@
 | 
				
			|||||||
                    <h2>Configuration</h2>
 | 
					                    <h2>Configuration</h2>
 | 
				
			||||||
                    <x-forms.button wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
 | 
					                    <x-forms.button wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="pt-3 pb-4">Custom (None) Proxy Selected</div>
 | 
					                <div class="pt-2 pb-4">Custom (None) Proxy Selected</div>
 | 
				
			||||||
            @else
 | 
					            @else
 | 
				
			||||||
                <div class="flex items-center gap-2">
 | 
					                <div class="flex items-center gap-2">
 | 
				
			||||||
                    <h2>Configuration</h2>
 | 
					                    <h2>Configuration</h2>
 | 
				
			||||||
@@ -57,14 +68,13 @@
 | 
				
			|||||||
                    </x-forms.button>
 | 
					                    </x-forms.button>
 | 
				
			||||||
                    <x-forms.button class="box" wire:click="select_proxy('TRAEFIK_V2')">
 | 
					                    <x-forms.button class="box" wire:click="select_proxy('TRAEFIK_V2')">
 | 
				
			||||||
                        Traefik
 | 
					                        Traefik
 | 
				
			||||||
                        v2
 | 
					                    </x-forms.button>
 | 
				
			||||||
 | 
					                    <x-forms.button class="box" wire:click="select_proxy('CADDY')">
 | 
				
			||||||
 | 
					                        Caddy (experimental)
 | 
				
			||||||
                    </x-forms.button>
 | 
					                    </x-forms.button>
 | 
				
			||||||
                    <x-forms.button disabled class="box">
 | 
					                    <x-forms.button disabled class="box">
 | 
				
			||||||
                        Nginx
 | 
					                        Nginx
 | 
				
			||||||
                    </x-forms.button>
 | 
					                    </x-forms.button>
 | 
				
			||||||
                    <x-forms.button disabled class="box">
 | 
					 | 
				
			||||||
                        Caddy
 | 
					 | 
				
			||||||
                    </x-forms.button>
 | 
					 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
    @endif
 | 
					    @endif
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user