From b997b7393b40f300ea1064cc84d304aeb8ae9911 Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 11 Oct 2024 02:44:52 +1100 Subject: [PATCH 1/8] feat: allow disabling default redirect, set status to 503 --- app/Listeners/ProxyStartedNotification.php | 2 +- app/Livewire/Server/Proxy.php | 16 +- app/Models/Server.php | 139 +++++++++--------- .../views/livewire/server/proxy.blade.php | 9 +- .../proxy/dynamic-configurations.blade.php | 2 +- 5 files changed, 91 insertions(+), 77 deletions(-) diff --git a/app/Listeners/ProxyStartedNotification.php b/app/Listeners/ProxyStartedNotification.php index d0541b162..9045b1e5c 100644 --- a/app/Listeners/ProxyStartedNotification.php +++ b/app/Listeners/ProxyStartedNotification.php @@ -14,7 +14,7 @@ class ProxyStartedNotification public function handle(ProxyStarted $event): void { $this->server = data_get($event, 'data'); - $this->server->setupDefault404Redirect(); + $this->server->setupDefaultRedirect(); $this->server->setupDynamicProxyConfiguration(); $this->server->proxy->force_stop = false; $this->server->save(); diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php index 55d0c4966..fbdba53c1 100644 --- a/app/Livewire/Server/Proxy.php +++ b/app/Livewire/Server/Proxy.php @@ -16,6 +16,7 @@ class Proxy extends Component public $proxy_settings = null; + public bool $redirect_enabled = true; public ?string $redirect_url = null; protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit']; @@ -27,6 +28,7 @@ class Proxy extends Component public function mount() { $this->selectedProxy = $this->server->proxyType(); + $this->redirect_enabled = data_get($this->server, 'proxy.redirect_enabled', true); $this->redirect_url = data_get($this->server, 'proxy.redirect_url'); } @@ -65,13 +67,25 @@ class Proxy extends Component } } + public function instantSaveRedirect() + { + try { + $this->server->proxy->redirect_enabled = $this->redirect_enabled; + $this->server->save(); + $this->server->setupDefaultRedirect(); + $this->dispatch('success', 'Proxy configuration saved.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function submit() { try { SaveConfiguration::run($this->server, $this->proxy_settings); $this->server->proxy->redirect_url = $this->redirect_url; $this->server->save(); - $this->server->setupDefault404Redirect(); + $this->server->setupDefaultRedirect(); $this->dispatch('success', 'Proxy configuration saved.'); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Models/Server.php b/app/Models/Server.php index 8864deef1..0a92caa60 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -94,6 +94,14 @@ class Server extends BaseModel ]); } } + if (!isset($server->proxy->redirect_enabled)) { + $server->proxy->redirect_enabled = true; + } + }); + static::retrieved(function ($server) { + if (!isset($server->proxy->redirect_enabled)) { + $server->proxy->redirect_enabled = true; + } }); static::deleting(function ($server) { $server->destinations()->each(function ($destination) { @@ -164,70 +172,72 @@ class Server extends BaseModel return $this->proxyType() && $this->proxyType() !== 'NONE' && $this->isFunctional() && ! $this->isSwarmWorker() && ! $this->settings->is_build_server; } - public function setupDefault404Redirect() + public function setupDefaultRedirect() { + $banner = + "# This file is generated by Coolify, do not edit it manually.\n" . + "# Disable the default redirect to customize (only if you know what are you doing).\n\n"; $dynamic_conf_path = $this->proxyPath().'/dynamic'; $proxy_type = $this->proxyType(); + $redirect_enabled = $this->proxy->redirect_enabled ?? true; $redirect_url = $this->proxy->redirect_url; + if ($proxy_type === ProxyTypes::TRAEFIK->value) { - $default_redirect_file = "$dynamic_conf_path/default_redirect_404.yaml"; + $default_redirect_file = "$dynamic_conf_path/default_redirect_503.yaml"; } elseif ($proxy_type === ProxyTypes::CADDY->value) { - $default_redirect_file = "$dynamic_conf_path/default_redirect_404.caddy"; + $default_redirect_file = "$dynamic_conf_path/default_redirect_503.caddy"; } - if (empty($redirect_url)) { + + instant_remote_process([ + "mkdir -p $dynamic_conf_path", + "rm -f $dynamic_conf_path/default_redirect_404.yaml", + "rm -f $dynamic_conf_path/default_redirect_404.caddy", + ], $this); + + if (!$redirect_enabled) { + instant_remote_process(["rm -f $default_redirect_file"], $this); + } else { if ($proxy_type === ProxyTypes::CADDY->value) { - $conf = ':80, :443 { -respond 404 + if (empty($redirect_url)) { + $conf = ':80, :443 { + respond 503 }'; - $conf = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". - $conf; - $base64 = base64_encode($conf); - instant_remote_process([ - "mkdir -p $dynamic_conf_path", - "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null", - ], $this); - $this->reloadCaddy(); - - return; - } - instant_remote_process([ - "mkdir -p $dynamic_conf_path", - "rm -f $default_redirect_file", - ], $this); - - return; - } - if ($proxy_type === ProxyTypes::TRAEFIK->value) { - $dynamic_conf = [ - 'http' => [ - 'routers' => [ - 'catchall' => [ - 'entryPoints' => [ - 0 => 'http', - 1 => 'https', - ], - 'service' => 'noop', - 'rule' => 'HostRegexp(`{catchall:.*}`)', - 'priority' => 1, - 'middlewares' => [ - 0 => 'redirect-regexp@file', + } else { + $conf = ":80, :443 { + redir $redirect_url +}"; + } + } elseif ($proxy_type === ProxyTypes::TRAEFIK->value) { + $dynamic_conf = [ + 'http' => [ + 'routers' => [ + 'catchall' => [ + 'entryPoints' => [ + 0 => 'http', + 1 => 'https', + ], + 'service' => 'noop', + 'rule' => 'HostRegexp(`{catchall:.*}`)', + 'priority' => 1, ], ], - ], - 'services' => [ - 'noop' => [ - 'loadBalancer' => [ - 'servers' => [ - 0 => [ - 'url' => '', - ], + 'services' => [ + 'noop' => [ + 'loadBalancer' => [ + 'servers' => [], ], ], ], ], - 'middlewares' => [ + ]; + if (!empty($redirect_url)) { + $dynamic_conf['http']['routers']['catchall']['middlewares'] = [ + 0 => 'redirect-regexp@file', + ]; + $dynamic_conf['http']['services']['noop']['loadBalancer']['servers'][0] = [ + 'url' => '', + ]; + $dynamic_conf['http']['middlewares'] = [ 'redirect-regexp' => [ 'redirectRegex' => [ 'regex' => '(.*)', @@ -235,32 +245,17 @@ respond 404 'permanent' => false, ], ], - ], - ], - ]; - $conf = Yaml::dump($dynamic_conf, 12, 2); - $conf = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". - $conf; - - $base64 = base64_encode($conf); - } elseif ($proxy_type === ProxyTypes::CADDY->value) { - $conf = ":80, :443 { - redir $redirect_url -}"; - $conf = - "# This file is automatically generated by Coolify.\n". - "# Do not edit it manually (only if you know what are you doing).\n\n". - $conf; + ]; + } + $conf = Yaml::dump($dynamic_conf, 12, 2); + } + $conf = $banner . $conf; $base64 = base64_encode($conf); + instant_remote_process([ + "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null", + ], $this); } - instant_remote_process([ - "mkdir -p $dynamic_conf_path", - "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null", - ], $this); - if ($proxy_type === 'CADDY') { $this->reloadCaddy(); } diff --git a/resources/views/livewire/server/proxy.blade.php b/resources/views/livewire/server/proxy.blade.php index 25c3f7acd..5748a5876 100644 --- a/resources/views/livewire/server/proxy.blade.php +++ b/resources/views/livewire/server/proxy.blade.php @@ -28,6 +28,13 @@ id="server.settings.generate_exact_labels" label="Generate labels only for {{ str($server->proxyType())->title() }}" instantSave /> +
Default request handler
+
+ + @if ($redirect_enabled) + + @endif +
@if ($server->proxyType() === ProxyTypes::TRAEFIK->value)

Traefik

@elseif ($server->proxyType() === 'CADDY') @@ -40,8 +47,6 @@ configurations. @endif -
diff --git a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php index a8192cdb1..dd1fa59f0 100644 --- a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php +++ b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php @@ -29,7 +29,7 @@ @if (str_replace('|', '.', $fileName) === 'coolify.yaml' || str_replace('|', '.', $fileName) === 'Caddyfile' || str_replace('|', '.', $fileName) === 'coolify.caddy' || - str_replace('|', '.', $fileName) === 'default_redirect_404.caddy') + str_replace('|', '.', $fileName) === 'default_redirect_503.caddy')

File: {{ str_replace('|', '.', $fileName) }}

From 2f3503d8b8509ddc9904a2fc3ffc12c3cd98e7b4 Mon Sep 17 00:00:00 2001 From: Kael Date: Fri, 11 Oct 2024 03:24:46 +1100 Subject: [PATCH 2/8] fix: don't allow editing traefik config --- .../views/livewire/server/proxy/dynamic-configurations.blade.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php index dd1fa59f0..5499ea95b 100644 --- a/resources/views/livewire/server/proxy/dynamic-configurations.blade.php +++ b/resources/views/livewire/server/proxy/dynamic-configurations.blade.php @@ -29,6 +29,7 @@ @if (str_replace('|', '.', $fileName) === 'coolify.yaml' || str_replace('|', '.', $fileName) === 'Caddyfile' || str_replace('|', '.', $fileName) === 'coolify.caddy' || + str_replace('|', '.', $fileName) === 'default_redirect_503.yaml' || str_replace('|', '.', $fileName) === 'default_redirect_503.caddy')

File: {{ str_replace('|', '.', $fileName) }}

From f82d95e908861565bdccb1eaaffb3e79bf878f30 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 Dec 2024 13:07:56 +0100 Subject: [PATCH 3/8] refactor: update Traefik configuration for improved security and logging - Removed unnecessary volume mapping for production environment. - Added insecure API access and debug logging for development environment. - Ensured consistent handling of Docker provider exposure settings. - Updated certificate resolver storage path for clarity. --- bootstrap/helpers/proxy.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index a8ef0fe5a..463e89b6f 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -173,13 +173,12 @@ function generate_default_proxy_configuration(Server $server) ], 'volumes' => [ '/var/run/docker.sock:/var/run/docker.sock:ro', - "{$proxy_path}:/traefik", + ], 'command' => [ '--ping=true', '--ping.entrypoint=http', '--api.dashboard=true', - '--api.insecure=false', '--entrypoints.http.address=:80', '--entrypoints.https.address=:443', '--entrypoints.http.http.encodequerysemicolons=true', @@ -187,21 +186,26 @@ function generate_default_proxy_configuration(Server $server) '--entrypoints.https.http.encodequerysemicolons=true', '--entryPoints.https.http2.maxConcurrentStreams=50', '--entrypoints.https.http3', - '--providers.docker.exposedbydefault=false', '--providers.file.directory=/traefik/dynamic/', + '--providers.docker.exposedbydefault=false', '--providers.file.watch=true', '--certificatesresolvers.letsencrypt.acme.httpchallenge=true', - '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json', '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http', + '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json', ], 'labels' => $labels, ], ], ]; if (isDev()) { - // $config['services']['traefik']['command'][] = "--log.level=debug"; + $config['services']['traefik']['command'][] = '--api.insecure=true'; + $config['services']['traefik']['command'][] = '--log.level=debug'; $config['services']['traefik']['command'][] = '--accesslog.filepath=/traefik/access.log'; $config['services']['traefik']['command'][] = '--accesslog.bufferingsize=100'; + $config['services']['traefik']['volumes'][] = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/:/traefik'; + } else { + $config['services']['traefik']['command'][] = '--api.insecure=false'; + $config['services']['traefik']['volumes'][] = "{$proxy_path}:/traefik"; } if ($server->isSwarm()) { data_forget($config, 'services.traefik.container_name'); From 659309c5b4e493bd7270925f1512a430e459fa2b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 Dec 2024 13:08:04 +0100 Subject: [PATCH 4/8] refactor: improve proxy configuration and code consistency in Server model - Standardized spacing in conditional statements for better readability. - Updated proxy redirect handling to ensure default values are set correctly. - Modified dynamic configuration path concatenation for clarity. - Changed router rule to 'PathPrefix' and adjusted priority for better routing behavior. - Replaced empty check with 'filled' helper for improved code clarity. --- app/Models/Server.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/Models/Server.php b/app/Models/Server.php index 3ddea4f32..8c7c7b769 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -105,12 +105,12 @@ class Server extends BaseModel ]); } } - if (!isset($server->proxy->redirect_enabled)) { + if (! isset($server->proxy->redirect_enabled)) { $server->proxy->redirect_enabled = true; } }); static::retrieved(function ($server) { - if (!isset($server->proxy->redirect_enabled)) { + if (! isset($server->proxy->redirect_enabled)) { $server->proxy->redirect_enabled = true; } }); @@ -197,7 +197,7 @@ class Server extends BaseModel $banner = "# This file is generated by Coolify, do not edit it manually.\n". "# Disable the default redirect to customize (only if you know what are you doing).\n\n"; - $dynamic_conf_path = $this->proxyPath() . '/dynamic'; + $dynamic_conf_path = $this->proxyPath().'/dynamic'; $proxy_type = $this->proxyType(); $redirect_enabled = $this->proxy->redirect_enabled ?? true; $redirect_url = $this->proxy->redirect_url; @@ -214,7 +214,7 @@ class Server extends BaseModel "rm -f $dynamic_conf_path/default_redirect_404.caddy", ], $this); - if (!$redirect_enabled) { + if (! $redirect_enabled) { instant_remote_process(["rm -f $default_redirect_file"], $this); } else { if ($proxy_type === ProxyTypes::CADDY->value) { @@ -237,11 +237,8 @@ class Server extends BaseModel 1 => 'https', ], 'service' => 'noop', - 'rule' => 'HostRegexp(`.+`)', - 'tls' => [ - 'certResolver' => 'letsencrypt', - ], - 'priority' => 1, + 'rule' => 'PathPrefix(`/`)', + 'priority' => -1000, ], ], 'services' => [ @@ -253,10 +250,11 @@ class Server extends BaseModel ], ], ]; - if (!empty($redirect_url)) { + if (filled($redirect_url)) { $dynamic_conf['http']['routers']['catchall']['middlewares'] = [ 0 => 'redirect-regexp', ]; + $dynamic_conf['http']['services']['noop']['loadBalancer']['servers'][0] = [ 'url' => '', ]; @@ -607,6 +605,7 @@ $schema://$host { $memory = json_decode($memory, true); $parsedCollection = collect($memory)->map(function ($metric) { $usedPercent = $metric['usedPercent'] ?? 0.0; + return [(int) $metric['time'], (float) $usedPercent]; }); From baf6c20997e16c2a979c45542a2f352424965fe0 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 Dec 2024 13:31:55 +0100 Subject: [PATCH 5/8] fix: restart proxy --- app/Livewire/Server/Proxy/Deploy.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Livewire/Server/Proxy/Deploy.php b/app/Livewire/Server/Proxy/Deploy.php index 8fcff85d6..4f9d41092 100644 --- a/app/Livewire/Server/Proxy/Deploy.php +++ b/app/Livewire/Server/Proxy/Deploy.php @@ -65,7 +65,7 @@ class Deploy extends Component public function restart() { try { - $this->stop(forceStop: false); + $this->stop(); $this->dispatch('checkProxy'); } catch (\Throwable $e) { return handleError($e, $this); @@ -105,6 +105,7 @@ class Deploy extends Component $startTime = Carbon::now()->getTimestamp(); while ($process->running()) { + ray('running'); if (Carbon::now()->getTimestamp() - $startTime >= $timeout) { $this->forceStopContainer($containerName); break; From e84dba493e7eb1d57b8e696d2fb7e32b835c0718 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 Dec 2024 13:39:00 +0100 Subject: [PATCH 6/8] fix --- app/Actions/Proxy/StartProxy.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php index 7c93720cb..9bc506d9b 100644 --- a/app/Actions/Proxy/StartProxy.php +++ b/app/Actions/Proxy/StartProxy.php @@ -2,6 +2,7 @@ namespace App\Actions\Proxy; +use App\Enums\ProxyTypes; use App\Events\ProxyStarted; use App\Models\Server; use Lorisleiva\Actions\Concerns\AsAction; @@ -37,11 +38,16 @@ class StartProxy "echo 'Successfully started coolify-proxy.'", ]); } else { - $caddfile = 'import /dynamic/*.caddy'; + if (isDev()) { + if ($proxyType === ProxyTypes::CADDY->value) { + $proxy_path = '/data/coolify/proxy/caddy'; + } + } + $caddyfile = 'import /dynamic/*.caddy'; $commands = $commands->merge([ "mkdir -p $proxy_path/dynamic", "cd $proxy_path", - "echo '$caddfile' > $proxy_path/dynamic/Caddyfile", + "echo '$caddyfile' > $proxy_path/dynamic/Caddyfile", "echo 'Creating required Docker Compose file.'", "echo 'Pulling docker image.'", 'docker compose pull', From 5453b9030ef61842824a153fcb8d960e07613002 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 Dec 2024 13:39:20 +0100 Subject: [PATCH 7/8] fix: dev mode --- app/Models/Server.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/Models/Server.php b/app/Models/Server.php index 8c7c7b769..4c4ca774f 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -201,7 +201,11 @@ class Server extends BaseModel $proxy_type = $this->proxyType(); $redirect_enabled = $this->proxy->redirect_enabled ?? true; $redirect_url = $this->proxy->redirect_url; - + if (isDev()) { + if ($proxy_type === ProxyTypes::CADDY->value) { + $dynamic_conf_path = '/data/coolify/proxy/caddy/dynamic'; + } + } if ($proxy_type === ProxyTypes::TRAEFIK->value) { $default_redirect_file = "$dynamic_conf_path/default_redirect_503.yaml"; } elseif ($proxy_type === ProxyTypes::CADDY->value) { @@ -214,18 +218,18 @@ class Server extends BaseModel "rm -f $dynamic_conf_path/default_redirect_404.caddy", ], $this); - if (! $redirect_enabled) { + if ($redirect_enabled === false) { instant_remote_process(["rm -f $default_redirect_file"], $this); } else { if ($proxy_type === ProxyTypes::CADDY->value) { - if (empty($redirect_url)) { + if (filled($redirect_url)) { + $conf = ":80, :443 { + redir $redirect_url +}"; + } else { $conf = ':80, :443 { respond 503 }'; - } else { - $conf = ":80, :443 { - redir $redirect_url -}"; } } elseif ($proxy_type === ProxyTypes::TRAEFIK->value) { $dynamic_conf = [ From 2b8b85618153f976e77d398c55670b7f313f4045 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 Dec 2024 13:39:28 +0100 Subject: [PATCH 8/8] fix: ui --- resources/views/livewire/server/proxy.blade.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/views/livewire/server/proxy.blade.php b/resources/views/livewire/server/proxy.blade.php index 5748a5876..00e0b04b2 100644 --- a/resources/views/livewire/server/proxy.blade.php +++ b/resources/views/livewire/server/proxy.blade.php @@ -27,12 +27,12 @@ helper="If set, all resources will only have docker container labels for {{ str($server->proxyType())->title() }}.
For applications, labels needs to be regenerated manually.
Resources needs to be restarted." id="server.settings.generate_exact_labels" label="Generate labels only for {{ str($server->proxyType())->title() }}" instantSave /> -
-
Default request handler
-
- + @if ($redirect_enabled) - + @endif
@if ($server->proxyType() === ProxyTypes::TRAEFIK->value)