From 59e37e14568dfb5fcbe52413a90b79f0661bad51 Mon Sep 17 00:00:00 2001 From: Simon <119116740+Seym0n@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:02:42 +0200 Subject: [PATCH 01/28] fix: unsend template In the previous template, the mapping of the web app was misconfigured due to the hostname not being set and the missing ports. Furthermore, the health check url was modified. --- templates/compose/unsend.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/templates/compose/unsend.yaml b/templates/compose/unsend.yaml index 649b7f704..bb5668038 100644 --- a/templates/compose/unsend.yaml +++ b/templates/compose/unsend.yaml @@ -35,6 +35,8 @@ services: unsend: image: unsend/unsend:latest + ports: + - "3000:3000" environment: - SERVICE_FQDN_UNSEND_3000 - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${SERVICE_DB_POSTGRES:-unsend} @@ -48,13 +50,14 @@ services: - REDIS_URL=redis://redis:6379 - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false} - API_RATE_LIMIT=${API_RATE_LIMIT:-1} + - HOSTNAME=0.0.0.0 depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: - test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:3000 || exit 1" ] + test: [ "CMD-SHELL", "wget -qO- http://unsend:3000 || exit 1" ] interval: 5s retries: 10 timeout: 2s From 786271d7be5ef5c7176a51602fab2d2a4a253148 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:29:36 +0200 Subject: [PATCH 02/28] chore(versions): bump coolify version to 4.0.0-beta.410 and update nightly version to 4.0.0-beta.411 in configuration files --- config/constants.php | 2 +- other/nightly/versions.json | 4 ++-- versions.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/constants.php b/config/constants.php index e7c7b68b9..c057a85db 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,7 +2,7 @@ return [ 'coolify' => [ - 'version' => '4.0.0-beta.409', + 'version' => '4.0.0-beta.410', 'helper_version' => '1.0.8', 'realtime_version' => '1.0.7', 'self_hosted' => env('SELF_HOSTED', true), diff --git a/other/nightly/versions.json b/other/nightly/versions.json index e940b635b..43fa56cca 100644 --- a/other/nightly/versions.json +++ b/other/nightly/versions.json @@ -1,10 +1,10 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.409" + "version": "4.0.0-beta.410" }, "nightly": { - "version": "4.0.0-beta.410" + "version": "4.0.0-beta.411" }, "helper": { "version": "1.0.8" diff --git a/versions.json b/versions.json index e940b635b..43fa56cca 100644 --- a/versions.json +++ b/versions.json @@ -1,10 +1,10 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.409" + "version": "4.0.0-beta.410" }, "nightly": { - "version": "4.0.0-beta.410" + "version": "4.0.0-beta.411" }, "helper": { "version": "1.0.8" From 4147300f659af59c0d0f0042809084e8fc40d17d Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:43:39 +0200 Subject: [PATCH 03/28] feat(readme): add new sponsors Supadata AI and WZ-IT to the README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8670e9c76..139112a55 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ Special thanks to our biggest sponsors! * [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly. * [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. * [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - A Fast web hosting provider. +* [Supadata AI](https://supadata.ai/?ref=coolify.io) - Scrape YouTube, web, and files. Get AI-ready, clean data for your next project. +* [WZ-IT](https://wz-it.com/?ref=coolify.io) - German agency for customised cloud solutions, migration, managed services and open source hosting, specialising in consulting and implementation of tailor-made cloud infrastructures for SMEs. ## Github Sponsors ($40+) From 89bf1b30cb442e454e1d3f9d91e8988350260556 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:09:45 +0200 Subject: [PATCH 04/28] fix(application): append base directory to git branch URLs for improved path handling --- app/Models/Application.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Models/Application.php b/app/Models/Application.php index 2feaebf94..4ee41651d 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -455,22 +455,23 @@ class Application extends BaseModel { return Attribute::make( get: function () { + $base_dir = $this->base_directory ?? '/'; if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) { if (str($this->git_repository)->contains('bitbucket')) { - return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}"; + return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}{$base_dir}"; } - return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}"; + return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}{$base_dir}"; } // Convert the SSH URL to HTTPS URL if (strpos($this->git_repository, 'git@') === 0) { $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository); if (str($this->git_repository)->contains('bitbucket')) { - return "https://{$git_repository}/src/{$this->git_branch}"; + return "https://{$git_repository}/src/{$this->git_branch}{$base_dir}"; } - return "https://{$git_repository}/tree/{$this->git_branch}"; + return "https://{$git_repository}/tree/{$this->git_branch}{$base_dir}"; } return $this->git_repository; From 618e5469669923fe57fa4d04e5c9b87011dd84fe Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:26:40 +0200 Subject: [PATCH 05/28] feat(core): Enable magic env variables for compose based applications --- bootstrap/helpers/shared.php | 291 +++++++++++++++++------------------ 1 file changed, 141 insertions(+), 150 deletions(-) diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 72b92e95a..aa821dc22 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3014,168 +3014,159 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int $savedService->image = $image; $savedService->save(); } + } + $environment = collect(data_get($service, 'environment', [])); + $buildArgs = collect(data_get($service, 'build.args', [])); + $environment = $environment->merge($buildArgs); - $environment = collect(data_get($service, 'environment', [])); - $buildArgs = collect(data_get($service, 'build.args', [])); - $environment = $environment->merge($buildArgs); + // convert environment variables to one format + $environment = convertToKeyValueCollection($environment); - // convert environment variables to one format - $environment = convertToKeyValueCollection($environment); + // Add Coolify defined environments + $allEnvironments = $resource->environment_variables()->get(['key', 'value']); - // Add Coolify defined environments - $allEnvironments = $resource->environment_variables()->get(['key', 'value']); + $allEnvironments = $allEnvironments->mapWithKeys(function ($item) { + return [$item['key'] => $item['value']]; + }); + // filter and add magic environments + foreach ($environment as $key => $value) { + // Get all SERVICE_ variables from keys and values + $key = str($key); + $value = str($value); - $allEnvironments = $allEnvironments->mapWithKeys(function ($item) { - return [$item['key'] => $item['value']]; - }); - // filter and add magic environments - foreach ($environment as $key => $value) { - // Get all SERVICE_ variables from keys and values - $key = str($key); - $value = str($value); - - $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/'; - preg_match_all($regex, $value, $valueMatches); - if (count($valueMatches[1]) > 0) { - foreach ($valueMatches[1] as $match) { - $match = replaceVariables($match); - if ($match->startsWith('SERVICE_')) { - if ($magicEnvironments->has($match->value())) { - continue; - } - $magicEnvironments->put($match->value(), ''); + $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/'; + preg_match_all($regex, $value, $valueMatches); + if (count($valueMatches[1]) > 0) { + foreach ($valueMatches[1] as $match) { + $match = replaceVariables($match); + if ($match->startsWith('SERVICE_')) { + if ($magicEnvironments->has($match->value())) { + continue; } - } - } - - // Get magic environments where we need to preset the FQDN - if ($key->startsWith('SERVICE_FQDN_')) { - // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000 - if (substr_count(str($key)->value(), '_') === 3) { - $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value(); - $port = $key->afterLast('_')->value(); - } else { - $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); - $port = null; - } - if ($isApplication) { - $fqdn = generateFqdn($server, "{$resource->name}-$uuid"); - } elseif ($isService) { - if ($fqdnFor) { - $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); - } else { - $fqdn = generateFqdn($server, "{$savedService->name}-$uuid"); - } - } - - if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) { - $path = $value->value(); - if ($path !== '/') { - $fqdn = "$fqdn$path"; - } - } - $fqdnWithPort = $fqdn; - if ($port) { - $fqdnWithPort = "$fqdn:$port"; - } - if ($isApplication && is_null($resource->fqdn)) { - data_forget($resource, 'environment_variables'); - data_forget($resource, 'environment_variables_preview'); - $resource->fqdn = $fqdnWithPort; - $resource->save(); - } elseif ($isService && is_null($savedService->fqdn)) { - $savedService->fqdn = $fqdnWithPort; - $savedService->save(); - } - - if (substr_count(str($key)->value(), '_') === 2) { - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); - } - if (substr_count(str($key)->value(), '_') === 3) { - $newKey = str($key)->beforeLast('_'); - $resource->environment_variables()->firstOrCreate([ - 'key' => $newKey->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); + $magicEnvironments->put($match->value(), ''); } } } - $allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments); - if ($magicEnvironments->count() > 0) { - foreach ($magicEnvironments as $key => $value) { - $key = str($key); - $value = replaceVariables($value); - $command = parseCommandFromMagicEnvVariable($key); - $found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first(); - if ($found) { - continue; - } - if ($command->value() === 'FQDN') { - $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); - if (str($fqdnFor)->contains('_')) { - $fqdnFor = str($fqdnFor)->before('_'); - } - if ($isApplication) { - $fqdn = generateFqdn($server, "{$resource->name}-$uuid"); - } elseif ($isService) { - $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); - } - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); - } elseif ($command->value() === 'URL') { - $fqdnFor = $key->after('SERVICE_URL_')->lower()->value(); - if (str($fqdnFor)->contains('_')) { - $fqdnFor = str($fqdnFor)->before('_'); - } - if ($isApplication) { - $fqdn = generateFqdn($server, "{$resource->name}-$uuid"); - } elseif ($isService) { - $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); - } - $fqdn = str($fqdn)->replace('http://', '')->replace('https://', ''); - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $fqdn, - 'is_build_time' => false, - 'is_preview' => false, - ]); + // Get magic environments where we need to preset the FQDN + if ($key->startsWith('SERVICE_FQDN_')) { + // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000 + if (substr_count(str($key)->value(), '_') === 3) { + $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value(); + $port = $key->afterLast('_')->value(); + } else { + $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); + $port = null; + } + if ($isApplication) { + $fqdn = generateFqdn($server, "$uuid"); + } elseif ($isService) { + if ($fqdnFor) { + $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); } else { - $value = generateEnvValue($command, $resource); - $resource->environment_variables()->firstOrCreate([ - 'key' => $key->value(), - 'resourceable_type' => get_class($resource), - 'resourceable_id' => $resource->id, - ], [ - 'value' => $value, - 'is_build_time' => false, - 'is_preview' => false, - ]); + $fqdn = generateFqdn($server, "{$savedService->name}-$uuid"); } } + + if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) { + $path = $value->value(); + if ($path !== '/') { + $fqdn = "$fqdn$path"; + } + } + $fqdnWithPort = $fqdn; + if ($port) { + $fqdnWithPort = "$fqdn:$port"; + } + if ($isApplication && is_null($resource->fqdn)) { + data_forget($resource, 'environment_variables'); + data_forget($resource, 'environment_variables_preview'); + $resource->fqdn = $fqdnWithPort; + $resource->save(); + } elseif ($isService && is_null($savedService->fqdn)) { + $savedService->fqdn = $fqdnWithPort; + $savedService->save(); + } + + if (substr_count(str($key)->value(), '_') === 2) { + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } + if (substr_count(str($key)->value(), '_') === 3) { + $newKey = str($key)->beforeLast('_'); + $resource->environment_variables()->firstOrCreate([ + 'key' => $newKey->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } + } + } + + $allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments); + if ($magicEnvironments->count() > 0) { + foreach ($magicEnvironments as $key => $value) { + $key = str($key); + $value = replaceVariables($value); + $command = parseCommandFromMagicEnvVariable($key); + $found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first(); + if ($found) { + continue; + } + if ($command->value() === 'FQDN') { + $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); + if (str($fqdnFor)->contains('_')) { + $fqdnFor = str($fqdnFor)->before('_'); + } + $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } elseif ($command->value() === 'URL') { + $fqdnFor = $key->after('SERVICE_URL_')->lower()->value(); + if (str($fqdnFor)->contains('_')) { + $fqdnFor = str($fqdnFor)->before('_'); + } + $fqdn = generateFqdn($server, "$fqdnFor-$uuid"); + $fqdn = str($fqdn)->replace('http://', '')->replace('https://', ''); + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $fqdn, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } else { + $value = generateEnvValue($command, $resource); + $resource->environment_variables()->firstOrCreate([ + 'key' => $key->value(), + 'resourceable_type' => get_class($resource), + 'resourceable_id' => $resource->id, + ], [ + 'value' => $value, + 'is_build_time' => false, + 'is_preview' => false, + ]); + } } } } From b88eae9669d3db72092841ee099ccf91b1d18ab2 Mon Sep 17 00:00:00 2001 From: Simon <119116740+Seym0n@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:51:06 +0200 Subject: [PATCH 06/28] fix: replace ports with expose This replaces the ports block with expose block --- templates/compose/unsend.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/compose/unsend.yaml b/templates/compose/unsend.yaml index bb5668038..32323f4bb 100644 --- a/templates/compose/unsend.yaml +++ b/templates/compose/unsend.yaml @@ -35,8 +35,8 @@ services: unsend: image: unsend/unsend:latest - ports: - - "3000:3000" + expose: + - 3000 environment: - SERVICE_FQDN_UNSEND_3000 - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${SERVICE_DB_POSTGRES:-unsend} From 7d698fafd05835eb14949e5fb0d9fe7a51899725 Mon Sep 17 00:00:00 2001 From: Nurdism Date: Wed, 16 Apr 2025 20:45:58 -0400 Subject: [PATCH 07/28] Fix #5074 & #5611 This prevents queues from getting stuck when using the WithoutOverlapping middleware --- app/Jobs/DockerCleanupJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index 05a4aa8de..7e246649d 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -31,7 +31,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(600)]; } public function __construct(public Server $server, public bool $manualCleanup = false) {} From 79ce3d8ddf2c57d01b7596f81c271678727c6807 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 17 Apr 2025 09:36:59 +0200 Subject: [PATCH 08/28] fix(templates): correct casing of "denokv" to "denoKV" in service templates JSON --- templates/service-templates.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/service-templates.json b/templates/service-templates.json index 0ee5ddb51..f4d119bc9 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -563,7 +563,7 @@ "minversion": "0.0.0", "port": "8080" }, - "denokv": { + "denoKV": { "documentation": "https://docs.deno.com/deploy/kv/manual/?utm_source=coolify.io", "slogan": "The Denoland key-value database", "compose": "c2VydmljZXM6CiAgZGVub2t2OgogICAgaW1hZ2U6ICdnaGNyLmlvL2Rlbm9sYW5kL2Rlbm9rdjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnQUNDRVNTX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9ERU5PS1Z9JwogICAgICAtIFNFUlZJQ0VfRlFETl9ERU5PS1ZfNDUxMgogICAgdm9sdW1lczoKICAgICAgLSAnJHtDT09MSUZZX1ZPTFVNRV9BUFB9Oi9kYXRhJwogICAgY29tbWFuZDogJy0tc3FsaXRlLXBhdGggL2RhdGEvZGVub2t2LnNxbGl0ZSBzZXJ2ZSAtLWFjY2Vzcy10b2tlbiAke1NFUlZJQ0VfUEFTU1dPUkRfREVOT0tWfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBuYwogICAgICAgIC0gJy16dicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzQ1MTInCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCg==", From 151b4b69d21491fec21a4c6388ab8a70a08c2593 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 17 Apr 2025 09:50:26 +0200 Subject: [PATCH 09/28] chore(templates): update plausible and clickhouse images to latest versions and remove mail service --- templates/compose/plausible.yaml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/templates/compose/plausible.yaml b/templates/compose/plausible.yaml index 71dfbe378..9bbacc508 100644 --- a/templates/compose/plausible.yaml +++ b/templates/compose/plausible.yaml @@ -6,7 +6,7 @@ services: plausible: - image: "ghcr.io/plausible/community-edition:v2.1.4" + image: "ghcr.io/plausible/community-edition:v3.0.1" command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"' environment: - SERVICE_FQDN_PLAUSIBLE @@ -17,13 +17,19 @@ services: - TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP} - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID} - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET} + - MAILER_ADAPTER=${MAILER_ADAPTER:-Bamboo.LocalAdapter} + - MAILER_EMAIL=${MAILER_EMAIL} + - MAILER_NAME=${MAILER_NAME} + - SMTP_HOST_ADDR=${SMTP_HOST_ADDR} + - SMTP_HOST_PORT=${SMTP_HOST_PORT} + - SMTP_USER_NAME=${SMTP_USER_NAME} + - SMTP_USER_PWD=${SMTP_USER_PWD} + - SMTP_HOST_SSL_ENABLED=${SMTP_HOST_SSL_ENABLED} depends_on: plausible-db: condition: service_healthy plausible-events-db: condition: service_healthy - mail: - condition: service_healthy healthcheck: test: [ @@ -39,15 +45,6 @@ services: retries: 5 start_period: 45s - mail: - image: bytemark/smtp - platform: linux/amd64 - healthcheck: - test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/25' || exit 1"] - interval: 5s - timeout: 10s - retries: 20 - plausible-db: image: "postgres:16-alpine" volumes: @@ -63,7 +60,9 @@ services: retries: 10 plausible-events-db: - image: "clickhouse/clickhouse-server:24.3.3.102-alpine" + image: "clickhouse/clickhouse-server:24.12-alpine" + environment: + - CLICKHOUSE_SKIP_USER_SETUP=1 volumes: - plausible-events-data:/var/lib/clickhouse - type: bind From b78f2cccff29821adc0c6b2ec41976f7a67c5a82 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 18 Apr 2025 09:52:32 +0200 Subject: [PATCH 10/28] refactor(jobs): update WithoutOverlapping middleware to use expireAfter for better queue management --- app/Jobs/CleanupInstanceStuffsJob.php | 4 +++- app/Jobs/PushServerUpdateJob.php | 2 +- app/Jobs/RestartProxyJob.php | 2 +- app/Jobs/ServerCheckJob.php | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/Jobs/CleanupInstanceStuffsJob.php b/app/Jobs/CleanupInstanceStuffsJob.php index 84f14ed02..008492342 100644 --- a/app/Jobs/CleanupInstanceStuffsJob.php +++ b/app/Jobs/CleanupInstanceStuffsJob.php @@ -17,11 +17,13 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + public $timeout = 60; + public function __construct() {} public function middleware(): array { - return [(new WithoutOverlapping('cleanup-instance-stuffs'))->dontRelease()]; + return [(new WithoutOverlapping('cleanup-instance-stuffs'))->expireAfter(60)]; } public function handle(): void diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 93b203fcb..4d40240f9 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -71,7 +71,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(30)]; } public function backoff(): int diff --git a/app/Jobs/RestartProxyJob.php b/app/Jobs/RestartProxyJob.php index 7fc716f70..4e1ade0da 100644 --- a/app/Jobs/RestartProxyJob.php +++ b/app/Jobs/RestartProxyJob.php @@ -24,7 +24,7 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(60)]; } public function __construct(public Server $server) {} diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 9818d5c6a..ffa298390 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -28,7 +28,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue public function middleware(): array { - return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; + return [(new WithoutOverlapping($this->server->uuid))->expireAfter(60)]; } public function __construct(public Server $server) {} From a501142ef529d4ed896677870df14b7f367f5688 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:32:32 +0200 Subject: [PATCH 11/28] fix(navbar): update error message link to use route for environment variables navigation --- resources/views/livewire/project/service/navbar.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/project/service/navbar.blade.php b/resources/views/livewire/project/service/navbar.blade.php index 7424f0940..3f3984116 100644 --- a/resources/views/livewire/project/service/navbar.blade.php +++ b/resources/views/livewire/project/service/navbar.blade.php @@ -129,7 +129,7 @@
From e2f44edc280ae933b1bfbe407b2530080c268124 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:33:17 +0200 Subject: [PATCH 12/28] fix(templates): update Unsend compose configuration for improved service integration --- templates/service-templates.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/service-templates.json b/templates/service-templates.json index f4d119bc9..be30cba5c 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -3083,7 +3083,7 @@ "unsend": { "documentation": "https://docs.unsend.dev/get-started/self-hosting?utm_source=coolify.io", "slogan": "Unsend is an open-source alternative to Resend, Sendgrid, Mailgun and Postmark etc.", - "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1VOU0VORF8zMDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9VTlNFTkR9JwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF82NF9ORVhUQVVUSFNFQ1JFVH0nCiAgICAgIC0gJ0FXU19BQ0NFU1NfS0VZPSR7QVdTX0FDQ0VTU19LRVk6P30nCiAgICAgIC0gJ0FXU19TRUNSRVRfS0VZPSR7QVdTX1NFQ1JFVF9LRVk6P30nCiAgICAgIC0gJ0FXU19ERUZBVUxUX1JFR0lPTj0ke0FXU19ERUZBVUxUX1JFR0lPTjo/fScKICAgICAgLSAnR0lUSFVCX0lEPSR7R0lUSFVCX0lEfScKICAgICAgLSAnR0lUSFVCX1NFQ1JFVD0ke0dJVEhVQl9TRUNSRVR9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9yZWRpczo2Mzc5JwogICAgICAtICdORVhUX1BVQkxJQ19JU19DTE9VRD0ke05FWFRfUFVCTElDX0lTX0NMT1VEOi1mYWxzZX0nCiAgICAgIC0gJ0FQSV9SQVRFX0xJTUlUPSR7QVBJX1JBVEVfTElNSVQ6LTF9JwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtcU8tIGh0dHA6Ly8xMjcuMC4wLjE6MzAwMCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiA1cwogICAgICByZXRyaWVzOiAxMAogICAgICB0aW1lb3V0OiAycwo=", + "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZXhwb3NlOgogICAgICAtIDMwMDAKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9VTlNFTkRfMzAwMAogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtTRVJWSUNFX0RCX1BPU1RHUkVTOi11bnNlbmR9JwogICAgICAtICdORVhUQVVUSF9VUkw9JHtTRVJWSUNFX0ZRRE5fVU5TRU5EfScKICAgICAgLSAnTkVYVEFVVEhfU0VDUkVUPSR7U0VSVklDRV9CQVNFNjRfNjRfTkVYVEFVVEhTRUNSRVR9JwogICAgICAtICdBV1NfQUNDRVNTX0tFWT0ke0FXU19BQ0NFU1NfS0VZOj99JwogICAgICAtICdBV1NfU0VDUkVUX0tFWT0ke0FXU19TRUNSRVRfS0VZOj99JwogICAgICAtICdBV1NfREVGQVVMVF9SRUdJT049JHtBV1NfREVGQVVMVF9SRUdJT046P30nCiAgICAgIC0gJ0dJVEhVQl9JRD0ke0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9TRUNSRVQ9JHtHSVRIVUJfU0VDUkVUfScKICAgICAgLSAnUkVESVNfVVJMPXJlZGlzOi8vcmVkaXM6NjM3OScKICAgICAgLSAnTkVYVF9QVUJMSUNfSVNfQ0xPVUQ9JHtORVhUX1BVQkxJQ19JU19DTE9VRDotZmFsc2V9JwogICAgICAtICdBUElfUkFURV9MSU1JVD0ke0FQSV9SQVRFX0xJTUlUOi0xfScKICAgICAgLSBIT1NUTkFNRT0wLjAuMC4wCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovL3Vuc2VuZDozMDAwIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHRpbWVvdXQ6IDJzCg==", "tags": [ "resend", "mailer", From 39e098569e4fdf52c99f9d15b3b8cffc3f4965a0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 18 Apr 2025 08:40:19 +0000 Subject: [PATCH 13/28] docs: update changelog --- CHANGELOG.md | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f80c646..eae126054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,18 @@ All notable changes to this project will be documented in this file. ### 🐛 Bug Fixes -- *(parser)* Transform associative array labels into key=value format for better compatibility -- *(redis)* Update username and password input handling to clarify database sync requirements -- *(source)* Update connected source display to handle cases with no source connected +- *(navbar)* Update error message link to use route for environment variables navigation +- Unsend template +- Replace ports with expose +- *(templates)* Update Unsend compose configuration for improved service integration ### 🚜 Refactor -- *(source)* Conditionally display connected source and change source options based on private key presence +- *(jobs)* Update WithoutOverlapping middleware to use expireAfter for better queue management -### ⚙️ Miscellaneous Tasks +### 📚 Documentation -- *(versions)* Bump coolify version to 4.0.0-beta.409 in configuration files +- Update changelog ## [4.0.0-beta.408] - 2025-04-14 @@ -24,6 +25,8 @@ All notable changes to this project will be documented in this file. - *(OpenApi)* Enhance OpenAPI specifications by adding UUID parameters for application, project, and service updates; improve deployment listing with pagination parameters; update command signature for OpenApi generation - *(subscription)* Enhance subscription management with loading states and Stripe status checks +- *(readme)* Add new sponsors Supadata AI and WZ-IT to the README +- *(core)* Enable magic env variables for compose based applications ### 🐛 Bug Fixes @@ -33,6 +36,11 @@ All notable changes to this project will be documented in this file. - *(mongodb)* Also apply custom config when SSL is enabled - *(templates)* Correct casing of denoKV references in service templates and YAML files - *(deployment)* Handle missing destination in deployment process to prevent errors +- *(parser)* Transform associative array labels into key=value format for better compatibility +- *(redis)* Update username and password input handling to clarify database sync requirements +- *(source)* Update connected source display to handle cases with no source connected +- *(application)* Append base directory to git branch URLs for improved path handling +- *(templates)* Correct casing of "denokv" to "denoKV" in service templates JSON ### 💼 Other @@ -44,6 +52,7 @@ All notable changes to this project will be documented in this file. - *(Dockerfile)* Remove service generation command from the build process to streamline Dockerfile and improve build efficiency - *(navbar-delete-team)* Simplify modal confirmation layout and enhance button styling for better user experience - *(Server)* Remove debug logging from isReachableChanged method to clean up code and improve performance +- *(source)* Conditionally display connected source and change source options based on private key presence ### 📚 Documentation @@ -56,6 +65,9 @@ All notable changes to this project will be documented in this file. - *(versions)* Update nightly version to 4.0.0-beta.410 - *(pre-commit)* Remove OpenAPI generation command from pre-commit hook - *(versions)* Update realtime version to 1.0.7 and bump dependencies in package.json +- *(versions)* Bump coolify version to 4.0.0-beta.409 in configuration files +- *(versions)* Bump coolify version to 4.0.0-beta.410 and update nightly version to 4.0.0-beta.411 in configuration files +- *(templates)* Update plausible and clickhouse images to latest versions and remove mail service ## [4.0.0-beta.407] - 2025-04-09 From a26d816fe3d26cf0508974ee50fd6e3652464e21 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sat, 19 Apr 2025 09:54:12 +0200 Subject: [PATCH 14/28] Update README.md --- README.md | 185 ++++++++++++++++++++++++++---------------------------- 1 file changed, 90 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 139112a55..6e245aa22 100644 --- a/README.md +++ b/README.md @@ -29,101 +29,6 @@ You can find the installation script source [here](./scripts/install.sh). Contact us at [coolify.io/docs/contact](https://coolify.io/docs/contact). -# Donations -To stay completely free and open-source, with no feature behind the paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the project's future development. - -[coolify.io/sponsorships](https://coolify.io/sponsorships) - -Thank you so much! - -Special thanks to our biggest sponsors! - -### Special Sponsors - -![image](https://github.com/user-attachments/assets/6022bc9c-8435-4d14-9497-8be230ed8cb1) - - -* [CCCareers](https://cccareers.org/) - A career development platform connecting coding bootcamp graduates with job opportunities in the tech industry. -* [Hetzner](http://htznr.li/CoolifyXHetzner) - A German web hosting company offering affordable dedicated servers, cloud services, and web hosting solutions. -* [Logto](https://logto.io/?ref=coolify) - An open-source authentication and authorization solution for building secure login systems and managing user identities. -* [Tolgee](https://tolgee.io/?ref=coolify) - Developer & translator friendly web-based localization platform. -* [BC Direct](https://bc.direct/?ref=coolify.io) - A digital marketing agency specializing in e-commerce solutions and online business growth strategies. -* [QuantCDN](https://www.quantcdn.io/?ref=coolify.io) - A content delivery network (CDN) optimizing website performance through global content distribution. -* [Arcjet](https://arcjet.com/?ref=coolify.io) - A cloud-based platform providing real-time protection against API abuse and bot attacks. -* [SupaGuide](https://supa.guide/?ref=coolify.io) - A comprehensive resource hub offering guides and tutorials for web development using Supabase. -* [GoldenVM](https://billing.goldenvm.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. -* [Tigris](https://tigrisdata.com/?ref=coolify.io) - A fully managed serverless object storage service compatible with Amazon S3 API. Offers high performance, scalability, and built-in search capabilities for efficient data management. -* [Convex](https://convex.link/coolify.io) - Convex is the open-source reactive database for web app developers. -* [Cloudify.ro](https://cloudify.ro/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. -* [Syntaxfm](https://syntax.fm/?ref=coolify.io) - Podcast for web developers. -* [PFGlabs](https://pfglabs.com/?ref=coolify.io) - Build real project with Golang. -* [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets. -* [Blacksmith](https://blacksmith.sh/?ref=coolify.io) - A cloud-native platform for automating infrastructure provisioning and management across multiple cloud providers. -* [Brand Dev](https://brand.dev/?ref=coolify.io) - The #1 Brand API for B2B software startups - instantly pull logos, fonts, descriptions, social links, slogans, and so much more from any domain via a single api call. -* [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries. -* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools. -* [Glueops](https://www.glueops.dev/?ref=coolify.io) - A DevOps consulting company providing infrastructure automation and cloud optimization services. -* [Ubicloud](https://ubicloud.com/?ref=coolify.io) - An open-source alternative to hyperscale cloud providers, offering high-performance cloud computing services. -* [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses. -* [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly. -* [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. -* [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - A Fast web hosting provider. -* [Supadata AI](https://supadata.ai/?ref=coolify.io) - Scrape YouTube, web, and files. Get AI-ready, clean data for your next project. -* [WZ-IT](https://wz-it.com/?ref=coolify.io) - German agency for customised cloud solutions, migration, managed services and open source hosting, specialising in consulting and implementation of tailor-made cloud infrastructures for SMEs. - - -## Github Sponsors ($40+) -SerpAPI -typebot - - -Lightspeed.run -DartNode - FlintCompany -American Cloud -CryptoJobsList -Codext -Thompson Edolo -UXWizz -Younes Barrad -Automaze -Corentin Clichy -Niklas Lausch -Pixel Infinito -Tyler Whitesides -NiftyCo -Imre Ujlaki -Ilias Ism -Breakcold -Paweł Pierścionek -Michael Mazurczak -Formbricks -StartupFame -jyc.dev -BitLaunch -Internet Garden -Jonas Jaeger -JP -Evercam -Web3 Career - -## Organizations - - - - - - - - - - - - -## Individuals - - - # Cloud If you do not want to self-host Coolify, there is a paid cloud version available: [app.coolify.io](https://app.coolify.io) @@ -139,6 +44,96 @@ By subscribing to the cloud version, you get the Coolify server for the same pri - Better support - Less maintenance for you +# Donations +To stay completely free and open-source, with no feature behind the paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the project's future development. + +[coolify.io/sponsorships](https://coolify.io/sponsorships) + +Thank you so much! + +## Big Sponsors + +* [GlueOps](https://www.glueops.dev?ref=coolify.io) - DevOps automation and infrastructure management +* [Algora](https://algora.io?ref=coolify.io) - Open source contribution platform +* [Ubicloud](https://www.ubicloud.com?ref=coolify.io) - Open source cloud infrastructure platform +* [LiquidWeb](https://liquidweb.com?ref=coolify.io) - Premium managed hosting solutions +* [Convex](https://convex.link/coolify.io) - Open-source reactive database for web app developers +* [Arcjet](https://arcjet.com?ref=coolify.io) - Advanced web security and performance solutions +* [SaasyKit](https://saasykit.com?ref=coolify.io) - Complete SaaS starter kit for developers +* [SupaGuide](https://supa.guide?ref=coolify.io) - Your comprehensive guide to Supabase +* [Logto](https://logto.io?ref=coolify.io) - The better identity infrastructure for developers +* [Trieve](https://trieve.ai?ref=coolify.io) - AI-powered search and analytics +* [Supadata AI](https://supadata.ai/?ref=coolify.io) - Scrape YouTube, web, and files. Get AI-ready, clean data +* [Darweb](https://darweb.nl/?ref=coolify.io) - Design. Develop. Deliver. Specialized in 3D CPQ Solutions +* [Hetzner](http://htznr.li/CoolifyXHetzner) - Server, cloud, hosting, and data center solutions +* [COMIT](https://comit.international?ref=coolify.io) - New York Times award–winning contractor +* [Blacksmith](https://blacksmith.sh?ref=coolify.io) - Infrastructure automation platform +* [WZ-IT](https://wz-it.com/?ref=coolify.io) - German agency for customised cloud solutions +* [BC Direct](https://bc.direct?ref=coolify.io) - Your trusted technology consulting partner +* [Tigris](https://www.tigrisdata.com?ref=coolify.io) - Modern developer data platform +* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - Web hosting and VPS solutions +* [QuantCDN](https://www.quantcdn.io?ref=coolify.io) - Enterprise-grade content delivery network +* [PFGLabs](https://pfglabs.com?ref=coolify.io) - Build Real Projects with Golang +* [JobsCollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - 30,000+ remote jobs for developers +* [Juxtdigital](https://juxtdigital.com?ref=coolify.io) - Digital transformation and web solutions +* [Cloudify.ro](https://cloudify.ro?ref=coolify.io) - Cloud hosting solutions +* [CodeRabbit](https://coderabbit.ai?ref=coolify.io) - Cut Code Review Time & Bugs in Half +* [American Cloud](https://americancloud.com?ref=coolify.io) - US-based cloud infrastructure services +* [MassiveGrid](https://massivegrid.com?ref=coolify.io) - Enterprise cloud hosting solutions +* [Syntax.fm](https://syntax.fm?ref=coolify.io) - Podcast for web developers +* [Tolgee](https://tolgee.io?ref=coolify.io) - The open source localization platform +* [CompAI](https://www.trycomp.ai?ref=coolify.io) - Open source compliance automation platform +* [GoldenVM](https://billing.goldenvm.com?ref=coolify.io) - Premium virtual machine hosting solutions + +## Small Sponsors + +UXWizz +Evercam +Imre Ujlaki +jyc.dev +TheRealJP +360Creators +NiftyCo +Dry Software +Lightspeed.run +LinkDr +Gravity Wiz +BitLaunch +Best for Android +Ilias Ism +Formbricks +Server Searcher +Reshot +Cirun +Typebot +Creating Coding Careers +Internet Garden +Web3 Jobs +Codext +Michael Mazurczak +Fider +Flint +Paweł Pierścionek +RunPod +DartNode +Tyler Whitesides +SerpAPI +Aquarela +Crypto Jobs List +Alfred Nutile +Startup Fame +Younes Barrad +Jonas Jaeger +Pixel Infinito +Corentin Clichy +Thompson Edolo +Devhuset +Arvensis Systems +Niklas Lausch +Cap-go + +...and many more at [GitHub Sponsors](https://github.com/sponsors/coollabsio) + # Recognitions

From 3f9228fb800ef9cd0fd313568c044bc01aff7907 Mon Sep 17 00:00:00 2001 From: Laurence Date: Sat, 19 Apr 2025 12:17:21 +0100 Subject: [PATCH 15/28] fix: Add 201 json code to servers validate api response --- app/Http/Controllers/Api/ServersController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index a9a0a2e53..cbd20400a 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -809,6 +809,6 @@ class ServersController extends Controller } ValidateServer::dispatch($server); - return response()->json(['message' => 'Validation started.']); + return response()->json(['message' => 'Validation started.'], 201); } } From c388e30499be2088e4933be33c6bcf23754f581d Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sun, 20 Apr 2025 17:58:41 +0200 Subject: [PATCH 16/28] refactor(jobs): comment out unused Caddy label handling in ApplicationDeploymentJob and simplify proxy path logic in Server model --- app/Jobs/ApplicationDeploymentJob.php | 38 +++++++++++++-------------- app/Models/Server.php | 6 +---- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index ab80a19de..b8141668d 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1712,25 +1712,25 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $labels = $labels->filter(function ($value, $key) { return ! Str::startsWith($value, 'coolify.'); }); - $found_caddy_labels = $labels->filter(function ($value, $key) { - return Str::startsWith($value, 'caddy_'); - }); - if ($found_caddy_labels->count() === 0) { - if ($this->pull_request_id !== 0) { - $domains = str(data_get($this->preview, 'fqdn'))->explode(','); - } else { - $domains = str(data_get($this->application, 'fqdn'))->explode(','); - } - $labels = $labels->merge(fqdnLabelsForCaddy( - network: $this->application->destination->network, - uuid: $this->application->uuid, - domains: $domains, - onlyPort: $onlyPort, - is_force_https_enabled: $this->application->isForceHttpsEnabled(), - is_gzip_enabled: $this->application->isGzipEnabled(), - is_stripprefix_enabled: $this->application->isStripprefixEnabled() - )); - } + // $found_caddy_labels = $labels->filter(function ($value, $key) { + // return Str::startsWith($value, 'caddy_'); + // }); + // if ($found_caddy_labels->count() === 0) { + // if ($this->pull_request_id !== 0) { + // $domains = str(data_get($this->preview, 'fqdn'))->explode(','); + // } else { + // $domains = str(data_get($this->application, 'fqdn'))->explode(','); + // } + // $labels = $labels->merge(fqdnLabelsForCaddy( + // network: $this->application->destination->network, + // uuid: $this->application->uuid, + // domains: $domains, + // onlyPort: $onlyPort, + // is_force_https_enabled: $this->application->isForceHttpsEnabled(), + // is_gzip_enabled: $this->application->isGzipEnabled(), + // is_stripprefix_enabled: $this->application->isStripprefixEnabled() + // )); + // } $this->application->custom_labels = base64_encode($labels->implode("\n")); $this->application->save(); } else { diff --git a/app/Models/Server.php b/app/Models/Server.php index 41af45f30..caf65cc58 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -492,11 +492,7 @@ $schema://$host { if ($proxyType === ProxyTypes::TRAEFIK->value) { // Do nothing } elseif ($proxyType === ProxyTypes::CADDY->value) { - if (isDev()) { - $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/caddy'; - } else { - $proxy_path = $proxy_path.'/caddy'; - } + $proxy_path = $proxy_path.'/caddy'; } elseif ($proxyType === ProxyTypes::NGINX->value) { if (isDev()) { $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx'; From 6d12e7edc7884b110667a2cb2e95dd5c2510ac31 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 21 Apr 2025 09:57:27 +0200 Subject: [PATCH 17/28] refactor(database): simplify database type checks in ServiceDatabase and enhance image validation in Docker helper --- app/Models/ServiceDatabase.php | 2 +- bootstrap/helpers/docker.php | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Models/ServiceDatabase.php b/app/Models/ServiceDatabase.php index c2a0df8cd..40d183033 100644 --- a/app/Models/ServiceDatabase.php +++ b/app/Models/ServiceDatabase.php @@ -141,6 +141,6 @@ class ServiceDatabase extends BaseModel str($this->databaseType())->contains('postgres') || str($this->databaseType())->contains('postgis') || str($this->databaseType())->contains('mariadb') || - str($this->databaseType())->contains('mongodb'); + str($this->databaseType())->contains('mongo'); } } diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index de80adbef..313df34a7 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -682,8 +682,10 @@ function isDatabaseImage(?string $image = null) $image = str($image)->append(':latest'); } $imageName = $image->before(':'); - if (collect(DATABASE_DOCKER_IMAGES)->contains($imageName)) { - return true; + foreach (DATABASE_DOCKER_IMAGES as $database_docker_image) { + if (str($imageName)->contains($database_docker_image)) { + return true; + } } return false; From 02b6aaaaf0c3d133e2c8a45d2dfcb511567a44cb Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 21 Apr 2025 09:58:56 +0200 Subject: [PATCH 18/28] refactor(shared): remove unused ray debugging statement from newParser function --- bootstrap/helpers/shared.php | 1 - 1 file changed, 1 deletion(-) diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index aa821dc22..44e20c9b3 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3819,7 +3819,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int return $volume; }); - ray($serviceLabels); $payload = collect($service)->merge([ 'container_name' => $containerName, 'restart' => $restart->value(), From 9548c7d3121e8da4453eddbb236b0314ec045310 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 21 Apr 2025 10:01:31 +0200 Subject: [PATCH 19/28] fix(backup-edit): conditionally enable S3 checkbox based on available validated S3 storage --- .../views/livewire/project/database/backup-edit.blade.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/resources/views/livewire/project/database/backup-edit.blade.php b/resources/views/livewire/project/database/backup-edit.blade.php index 603983864..f83af91a0 100644 --- a/resources/views/livewire/project/database/backup-edit.blade.php +++ b/resources/views/livewire/project/database/backup-edit.blade.php @@ -20,7 +20,12 @@

- + @if ($s3s->count() > 0) + + @else + + @endif
@if ($backup->save_s3)
From d731cdabdfe98c4bf0a663cf3a0f66cf2161063e Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:20:54 +0200 Subject: [PATCH 20/28] fix(source): update no sources found message for clarity --- resources/views/livewire/project/application/source.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/project/application/source.blade.php b/resources/views/livewire/project/application/source.blade.php index 56bace154..85382055e 100644 --- a/resources/views/livewire/project/application/source.blade.php +++ b/resources/views/livewire/project/application/source.blade.php @@ -81,7 +81,7 @@
@empty -
No sources found
+
No other sources found
@endforelse From cd2f71b463002da79864510e2dca60e59508c27a Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:20:57 +0200 Subject: [PATCH 21/28] feat(deployment): add repository_project_id handling for private GitHub apps and clean up unused Caddy label logic --- app/Jobs/ApplicationDeploymentJob.php | 30 ++++++++------------- app/Livewire/Project/Application/Source.php | 1 + 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index b8141668d..c29093ce0 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1377,6 +1377,17 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue private function check_git_if_build_needed() { + if ($this->source->getMorphClass() === \App\Models\GithubApp::class && $this->source->is_public === false) { + $repository = githubApi($this->source, "repos/{$this->customRepository}"); + $data = data_get($repository, 'data'); + if (isset($data->id)) { + $repository_project_id = $data->id; + if (blank($this->application->repository_project_id) || $this->application->repository_project_id !== $repository_project_id) { + $this->application->repository_project_id = $repository_project_id; + $this->application->save(); + } + } + } $this->generate_git_import_commands(); $local_branch = $this->branch; if ($this->pull_request_id !== 0) { @@ -1712,25 +1723,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $labels = $labels->filter(function ($value, $key) { return ! Str::startsWith($value, 'coolify.'); }); - // $found_caddy_labels = $labels->filter(function ($value, $key) { - // return Str::startsWith($value, 'caddy_'); - // }); - // if ($found_caddy_labels->count() === 0) { - // if ($this->pull_request_id !== 0) { - // $domains = str(data_get($this->preview, 'fqdn'))->explode(','); - // } else { - // $domains = str(data_get($this->application, 'fqdn'))->explode(','); - // } - // $labels = $labels->merge(fqdnLabelsForCaddy( - // network: $this->application->destination->network, - // uuid: $this->application->uuid, - // domains: $domains, - // onlyPort: $onlyPort, - // is_force_https_enabled: $this->application->isForceHttpsEnabled(), - // is_gzip_enabled: $this->application->isGzipEnabled(), - // is_stripprefix_enabled: $this->application->isStripprefixEnabled() - // )); - // } $this->application->custom_labels = base64_encode($labels->implode("\n")); $this->application->save(); } else { diff --git a/app/Livewire/Project/Application/Source.php b/app/Livewire/Project/Application/Source.php index 013d8b8fe..e27a550c1 100644 --- a/app/Livewire/Project/Application/Source.php +++ b/app/Livewire/Project/Application/Source.php @@ -111,6 +111,7 @@ class Source extends Component $this->application->update([ 'source_id' => $sourceId, 'source_type' => $sourceType, + 'repository_project_id' => null, ]); $this->application->refresh(); $this->getSources(); From 4ea00cff310f2a689257a29bad31aab404253f23 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:44:30 +0200 Subject: [PATCH 22/28] refactor(applications): remove redundant error response in create_env method --- app/Http/Controllers/Api/ApplicationsController.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index aa5f2ff14..f25f63b11 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -2562,10 +2562,6 @@ class ApplicationsController extends Controller ])->setStatusCode(201); } } - - return response()->json([ - 'message' => 'Something went wrong.', - ], 500); } #[OA\Delete( From 3160b8a5a5c4d24af58c7158133af7e7a0731b8a Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:44:37 +0200 Subject: [PATCH 23/28] feat(api): enhance OpenAPI specifications with token variable and additional key attributes --- app/Http/Controllers/Api/OpenApi.php | 4 +++- openapi.json | 14 +++++++++++++- openapi.yaml | 8 ++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/OpenApi.php b/app/Http/Controllers/Api/OpenApi.php index 60337a76c..ee75c1c6c 100644 --- a/app/Http/Controllers/Api/OpenApi.php +++ b/app/Http/Controllers/Api/OpenApi.php @@ -5,7 +5,9 @@ namespace App\Http\Controllers\Api; use OpenApi\Attributes as OA; #[OA\Info(title: 'Coolify', version: '0.1')] -#[OA\Server(url: 'https://app.coolify.io/api/v1', description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.')] +#[OA\Server(url: 'https://app.coolify.io/api/v1', description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.', variables: [ + new OA\ServerVariable('token', 'your-coolify-token-here', 'Coolify token for authentication'), +])] #[OA\SecurityScheme( type: 'http', scheme: 'bearer', diff --git a/openapi.json b/openapi.json index 5070f1be9..7f1aa637b 100644 --- a/openapi.json +++ b/openapi.json @@ -7,7 +7,13 @@ "servers": [ { "url": "https:\/\/app.coolify.io\/api\/v1", - "description": "Coolify Cloud API. Change the host to your own instance if you are self-hosting." + "description": "Coolify Cloud API. Change the host to your own instance if you are self-hosting.", + "variables": { + "token": { + "default": "Coolify token for authentication", + "description": "your-coolify-token-here" + } + } } ], "paths": { @@ -7729,6 +7735,12 @@ "type": "string", "format": "private-key" }, + "public_key": { + "type": "string" + }, + "fingerprint": { + "type": "string" + }, "is_git_related": { "type": "boolean" }, diff --git a/openapi.yaml b/openapi.yaml index 1fd42055b..07e1f82c2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -6,6 +6,10 @@ servers: - url: 'https://app.coolify.io/api/v1' description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.' + variables: + token: + default: 'Coolify token for authentication' + description: your-coolify-token-here paths: /applications: get: @@ -5159,6 +5163,10 @@ components: private_key: type: string format: private-key + public_key: + type: string + fingerprint: + type: string is_git_related: type: boolean team_id: From 91f28656350c0c11c860cf9851b6c25baf0a5157 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 11:05:55 +0200 Subject: [PATCH 24/28] refactor(api): restructure routes to include versioning and maintain existing feedback endpoint --- routes/api.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index b65e59e8b..ba78034d8 100644 --- a/routes/api.php +++ b/routes/api.php @@ -16,8 +16,13 @@ use App\Models\Server; use Illuminate\Support\Facades\Route; Route::get('/health', [OtherController::class, 'healthcheck']); -Route::post('/feedback', [OtherController::class, 'feedback']); +Route::group([ + 'prefix' => 'v1', +], function () { + Route::get('/health', [OtherController::class, 'healthcheck']); +}); +Route::post('/feedback', [OtherController::class, 'feedback']); Route::group([ 'middleware' => ['auth:sanctum', 'api.ability:write'], 'prefix' => 'v1', From 1d52df0e4eb892a046404a44c13f5078c75f32a6 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 11:12:30 +0200 Subject: [PATCH 25/28] refactor(api): remove token variable from OpenAPI specifications for clarity --- app/Http/Controllers/Api/OpenApi.php | 4 +--- openapi.json | 8 +------- openapi.yaml | 4 ---- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Api/OpenApi.php b/app/Http/Controllers/Api/OpenApi.php index ee75c1c6c..60337a76c 100644 --- a/app/Http/Controllers/Api/OpenApi.php +++ b/app/Http/Controllers/Api/OpenApi.php @@ -5,9 +5,7 @@ namespace App\Http\Controllers\Api; use OpenApi\Attributes as OA; #[OA\Info(title: 'Coolify', version: '0.1')] -#[OA\Server(url: 'https://app.coolify.io/api/v1', description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.', variables: [ - new OA\ServerVariable('token', 'your-coolify-token-here', 'Coolify token for authentication'), -])] +#[OA\Server(url: 'https://app.coolify.io/api/v1', description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.')] #[OA\SecurityScheme( type: 'http', scheme: 'bearer', diff --git a/openapi.json b/openapi.json index 7f1aa637b..b48bd85e9 100644 --- a/openapi.json +++ b/openapi.json @@ -7,13 +7,7 @@ "servers": [ { "url": "https:\/\/app.coolify.io\/api\/v1", - "description": "Coolify Cloud API. Change the host to your own instance if you are self-hosting.", - "variables": { - "token": { - "default": "Coolify token for authentication", - "description": "your-coolify-token-here" - } - } + "description": "Coolify Cloud API. Change the host to your own instance if you are self-hosting." } ], "paths": { diff --git a/openapi.yaml b/openapi.yaml index 07e1f82c2..239da6820 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -6,10 +6,6 @@ servers: - url: 'https://app.coolify.io/api/v1' description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.' - variables: - token: - default: 'Coolify token for authentication' - description: your-coolify-token-here paths: /applications: get: From bb8cc467ab53c1ea29014aa3c2f32e7340c684c3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 11:16:45 +0200 Subject: [PATCH 26/28] fix(api): correct middleware for service update route to ensure proper permissions --- routes/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index ba78034d8..405d8240e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -122,7 +122,7 @@ Route::group([ Route::post('/services', [ServicesController::class, 'create_service'])->middleware(['api.ability:write']); Route::get('/services/{uuid}', [ServicesController::class, 'service_by_uuid'])->middleware(['api.ability:read']); - Route::patch('/services/{uuid}', [ServicesController::class, 'update_by_uuid'])->middleware(['ability:write']); + Route::patch('/services/{uuid}', [ServicesController::class, 'update_by_uuid'])->middleware(['api.ability:write']); Route::delete('/services/{uuid}', [ServicesController::class, 'delete_by_uuid'])->middleware(['api.ability:write']); Route::get('/services/{uuid}/envs', [ServicesController::class, 'envs'])->middleware(['api.ability:read']); From eee57d4c06716c25ba7d599074ebc7baeb8d0db7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 11:16:49 +0200 Subject: [PATCH 27/28] fix(api): handle JSON response in service creation and update methods for improved error handling --- app/Http/Controllers/Api/ServicesController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index c3730d83f..e792779e1 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -380,6 +380,9 @@ class ServicesController extends Controller $service = new Service; $result = $this->upsert_service($request, $service, $teamId); + if ($result instanceof \Illuminate\Http\JsonResponse) { + return $result; + } return response()->json(serializeApiResponse($result))->setStatusCode(201); } else { @@ -608,12 +611,14 @@ class ServicesController extends Controller } $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first(); - if (! $service) { return response()->json(['message' => 'Service not found.'], 404); } $result = $this->upsert_service($request, $service, $teamId); + if ($result instanceof \Illuminate\Http\JsonResponse) { + return $result; + } return response()->json(serializeApiResponse($result))->setStatusCode(200); } From 00fe6e90034b848af0651fc68dbe4d932e72021c Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 22 Apr 2025 11:40:35 +0200 Subject: [PATCH 28/28] refactor(environment-variables): remove protected variable checks from delete methods for cleaner logic --- app/Livewire/Project/Shared/EnvironmentVariable/All.php | 9 --------- app/Livewire/Project/Shared/EnvironmentVariable/Show.php | 7 ------- 2 files changed, 16 deletions(-) diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php index 57952ddb3..699dca187 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php @@ -236,15 +236,6 @@ class All extends Component return 0; } - // Check for system variables that shouldn't be deleted - foreach ($variablesToDelete as $envVar) { - if ($this->isProtectedEnvironmentVariable($envVar->key)) { - $this->dispatch('error', "Cannot delete system environment variable '{$envVar->key}'."); - - return 0; - } - } - // Check if any of these variables are used in Docker Compose if ($this->resource->type() === 'service' || $this->resource->build_pack === 'dockercompose') { foreach ($variablesToDelete as $envVar) { diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php index d58151abf..535ac6c67 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php @@ -178,13 +178,6 @@ class Show extends Component public function delete() { try { - // Check if the variable is protected - if ($this->isProtectedEnvironmentVariable($this->env->key)) { - $this->dispatch('error', "Cannot delete system environment variable '{$this->env->key}'."); - - return; - } - // Check if the variable is used in Docker Compose if ($this->type === 'service' || $this->type === 'application' && $this->env->resource()?->docker_compose) { [$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resource()?->docker_compose);