@@ -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.
 | 
					* [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.
 | 
					* [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.
 | 
					* [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+)
 | 
					## Github Sponsors ($40+)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,13 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
					    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $timeout = 60;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct() {}
 | 
					    public function __construct() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function middleware(): array
 | 
					    public function middleware(): array
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return [(new WithoutOverlapping('cleanup-instance-stuffs'))->dontRelease()];
 | 
					        return [(new WithoutOverlapping('cleanup-instance-stuffs'))->expireAfter(60)];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function handle(): void
 | 
					    public function handle(): void
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function middleware(): array
 | 
					    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) {}
 | 
					    public function __construct(public Server $server, public bool $manualCleanup = false) {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,7 +71,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function middleware(): array
 | 
					    public function middleware(): array
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return [(new WithoutOverlapping($this->server->uuid))->dontRelease()];
 | 
					        return [(new WithoutOverlapping($this->server->uuid))->expireAfter(30)];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function backoff(): int
 | 
					    public function backoff(): int
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function middleware(): array
 | 
					    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) {}
 | 
					    public function __construct(public Server $server) {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function middleware(): array
 | 
					    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) {}
 | 
					    public function __construct(public Server $server) {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -455,22 +455,23 @@ class Application extends BaseModel
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return Attribute::make(
 | 
					        return Attribute::make(
 | 
				
			||||||
            get: function () {
 | 
					            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 (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
 | 
				
			||||||
                    if (str($this->git_repository)->contains('bitbucket')) {
 | 
					                    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
 | 
					                // Convert the SSH URL to HTTPS URL
 | 
				
			||||||
                if (strpos($this->git_repository, 'git@') === 0) {
 | 
					                if (strpos($this->git_repository, 'git@') === 0) {
 | 
				
			||||||
                    $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
 | 
					                    $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (str($this->git_repository)->contains('bitbucket')) {
 | 
					                    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;
 | 
					                return $this->git_repository;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3014,168 +3014,159 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
 | 
				
			|||||||
                $savedService->image = $image;
 | 
					                $savedService->image = $image;
 | 
				
			||||||
                $savedService->save();
 | 
					                $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', []));
 | 
					        // convert environment variables to one format
 | 
				
			||||||
            $buildArgs = collect(data_get($service, 'build.args', []));
 | 
					        $environment = convertToKeyValueCollection($environment);
 | 
				
			||||||
            $environment = $environment->merge($buildArgs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // convert environment variables to one format
 | 
					        // Add Coolify defined environments
 | 
				
			||||||
            $environment = convertToKeyValueCollection($environment);
 | 
					        $allEnvironments = $resource->environment_variables()->get(['key', 'value']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Add Coolify defined environments
 | 
					        $allEnvironments = $allEnvironments->mapWithKeys(function ($item) {
 | 
				
			||||||
            $allEnvironments = $resource->environment_variables()->get(['key', 'value']);
 | 
					            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) {
 | 
					            $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/';
 | 
				
			||||||
                return [$item['key'] => $item['value']];
 | 
					            preg_match_all($regex, $value, $valueMatches);
 | 
				
			||||||
            });
 | 
					            if (count($valueMatches[1]) > 0) {
 | 
				
			||||||
            // filter and add magic environments
 | 
					                foreach ($valueMatches[1] as $match) {
 | 
				
			||||||
            foreach ($environment as $key => $value) {
 | 
					                    $match = replaceVariables($match);
 | 
				
			||||||
                // Get all SERVICE_ variables from keys and values
 | 
					                    if ($match->startsWith('SERVICE_')) {
 | 
				
			||||||
                $key = str($key);
 | 
					                        if ($magicEnvironments->has($match->value())) {
 | 
				
			||||||
                $value = str($value);
 | 
					                            continue;
 | 
				
			||||||
 | 
					 | 
				
			||||||
                $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(), '');
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                        $magicEnvironments->put($match->value(), '');
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // 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,
 | 
					 | 
				
			||||||
                        ]);
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments);
 | 
					            // Get magic environments where we need to preset the FQDN
 | 
				
			||||||
            if ($magicEnvironments->count() > 0) {
 | 
					            if ($key->startsWith('SERVICE_FQDN_')) {
 | 
				
			||||||
                foreach ($magicEnvironments as $key => $value) {
 | 
					                // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000
 | 
				
			||||||
                    $key = str($key);
 | 
					                if (substr_count(str($key)->value(), '_') === 3) {
 | 
				
			||||||
                    $value = replaceVariables($value);
 | 
					                    $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value();
 | 
				
			||||||
                    $command = parseCommandFromMagicEnvVariable($key);
 | 
					                    $port = $key->afterLast('_')->value();
 | 
				
			||||||
                    $found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first();
 | 
					                } else {
 | 
				
			||||||
                    if ($found) {
 | 
					                    $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
 | 
				
			||||||
                        continue;
 | 
					                    $port = null;
 | 
				
			||||||
                    }
 | 
					                }
 | 
				
			||||||
                    if ($command->value() === 'FQDN') {
 | 
					                if ($isApplication) {
 | 
				
			||||||
                        $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
 | 
					                    $fqdn = generateFqdn($server, "$uuid");
 | 
				
			||||||
                        if (str($fqdnFor)->contains('_')) {
 | 
					                } elseif ($isService) {
 | 
				
			||||||
                            $fqdnFor = str($fqdnFor)->before('_');
 | 
					                    if ($fqdnFor) {
 | 
				
			||||||
                        }
 | 
					                        $fqdn = generateFqdn($server, "$fqdnFor-$uuid");
 | 
				
			||||||
                        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,
 | 
					 | 
				
			||||||
                        ]);
 | 
					 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        $value = generateEnvValue($command, $resource);
 | 
					                        $fqdn = generateFqdn($server, "{$savedService->name}-$uuid");
 | 
				
			||||||
                        $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,
 | 
					 | 
				
			||||||
                        ]);
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                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,
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
return [
 | 
					return [
 | 
				
			||||||
    'coolify' => [
 | 
					    'coolify' => [
 | 
				
			||||||
        'version' => '4.0.0-beta.409',
 | 
					        'version' => '4.0.0-beta.410',
 | 
				
			||||||
        'helper_version' => '1.0.8',
 | 
					        'helper_version' => '1.0.8',
 | 
				
			||||||
        'realtime_version' => '1.0.7',
 | 
					        'realtime_version' => '1.0.7',
 | 
				
			||||||
        'self_hosted' => env('SELF_HOSTED', true),
 | 
					        'self_hosted' => env('SELF_HOSTED', true),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "coolify": {
 | 
					    "coolify": {
 | 
				
			||||||
        "v4": {
 | 
					        "v4": {
 | 
				
			||||||
            "version": "4.0.0-beta.409"
 | 
					            "version": "4.0.0-beta.410"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "nightly": {
 | 
					        "nightly": {
 | 
				
			||||||
            "version": "4.0.0-beta.410"
 | 
					            "version": "4.0.0-beta.411"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "helper": {
 | 
					        "helper": {
 | 
				
			||||||
            "version": "1.0.8"
 | 
					            "version": "1.0.8"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,7 @@
 | 
				
			|||||||
            <div class="flex flex-wrap order-first gap-2 items-center sm:order-last">
 | 
					            <div class="flex flex-wrap order-first gap-2 items-center sm:order-last">
 | 
				
			||||||
                <div class="text-error">
 | 
					                <div class="text-error">
 | 
				
			||||||
                    Unable to deploy. <a class="underline font-bold cursor-pointer"
 | 
					                    Unable to deploy. <a class="underline font-bold cursor-pointer"
 | 
				
			||||||
                        @click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'">
 | 
					                        href="{{ route('project.service.environment-variables', $parameters) }}" wire:navigate>
 | 
				
			||||||
                        Required environment variables missing.</a>
 | 
					                        Required environment variables missing.</a>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
services:
 | 
					services:
 | 
				
			||||||
  plausible:
 | 
					  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"'
 | 
					    command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"'
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      - SERVICE_FQDN_PLAUSIBLE
 | 
					      - SERVICE_FQDN_PLAUSIBLE
 | 
				
			||||||
@@ -17,13 +17,19 @@ services:
 | 
				
			|||||||
      - TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP}
 | 
					      - TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP}
 | 
				
			||||||
      - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
 | 
					      - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
 | 
				
			||||||
      - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
 | 
					      - 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:
 | 
					    depends_on:
 | 
				
			||||||
      plausible-db:
 | 
					      plausible-db:
 | 
				
			||||||
        condition: service_healthy
 | 
					        condition: service_healthy
 | 
				
			||||||
      plausible-events-db:
 | 
					      plausible-events-db:
 | 
				
			||||||
        condition: service_healthy
 | 
					        condition: service_healthy
 | 
				
			||||||
      mail:
 | 
					 | 
				
			||||||
        condition: service_healthy
 | 
					 | 
				
			||||||
    healthcheck:
 | 
					    healthcheck:
 | 
				
			||||||
      test:
 | 
					      test:
 | 
				
			||||||
        [
 | 
					        [
 | 
				
			||||||
@@ -39,15 +45,6 @@ services:
 | 
				
			|||||||
      retries: 5
 | 
					      retries: 5
 | 
				
			||||||
      start_period: 45s
 | 
					      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:
 | 
					  plausible-db:
 | 
				
			||||||
    image: "postgres:16-alpine"
 | 
					    image: "postgres:16-alpine"
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
@@ -63,7 +60,9 @@ services:
 | 
				
			|||||||
      retries: 10
 | 
					      retries: 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  plausible-events-db:
 | 
					  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:
 | 
					    volumes:
 | 
				
			||||||
      - plausible-events-data:/var/lib/clickhouse
 | 
					      - plausible-events-data:/var/lib/clickhouse
 | 
				
			||||||
      - type: bind
 | 
					      - type: bind
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,8 @@ services:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  unsend:
 | 
					  unsend:
 | 
				
			||||||
    image: unsend/unsend:latest
 | 
					    image: unsend/unsend:latest
 | 
				
			||||||
 | 
					    expose:
 | 
				
			||||||
 | 
					      - 3000
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      - SERVICE_FQDN_UNSEND_3000
 | 
					      - SERVICE_FQDN_UNSEND_3000
 | 
				
			||||||
      - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${SERVICE_DB_POSTGRES:-unsend}
 | 
					      - 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
 | 
					      - REDIS_URL=redis://redis:6379
 | 
				
			||||||
      - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false}
 | 
					      - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false}
 | 
				
			||||||
      - API_RATE_LIMIT=${API_RATE_LIMIT:-1}
 | 
					      - API_RATE_LIMIT=${API_RATE_LIMIT:-1}
 | 
				
			||||||
 | 
					      - HOSTNAME=0.0.0.0
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
      postgres:
 | 
					      postgres:
 | 
				
			||||||
        condition: service_healthy
 | 
					        condition: service_healthy
 | 
				
			||||||
      redis:
 | 
					      redis:
 | 
				
			||||||
        condition: service_healthy
 | 
					        condition: service_healthy
 | 
				
			||||||
    healthcheck:
 | 
					    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
 | 
					      interval: 5s
 | 
				
			||||||
      retries: 10
 | 
					      retries: 10
 | 
				
			||||||
      timeout: 2s
 | 
					      timeout: 2s
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -563,7 +563,7 @@
 | 
				
			|||||||
        "minversion": "0.0.0",
 | 
					        "minversion": "0.0.0",
 | 
				
			||||||
        "port": "8080"
 | 
					        "port": "8080"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "denokv": {
 | 
					    "denoKV": {
 | 
				
			||||||
        "documentation": "https://docs.deno.com/deploy/kv/manual/?utm_source=coolify.io",
 | 
					        "documentation": "https://docs.deno.com/deploy/kv/manual/?utm_source=coolify.io",
 | 
				
			||||||
        "slogan": "The Denoland key-value database",
 | 
					        "slogan": "The Denoland key-value database",
 | 
				
			||||||
        "compose": "c2VydmljZXM6CiAgZGVub2t2OgogICAgaW1hZ2U6ICdnaGNyLmlvL2Rlbm9sYW5kL2Rlbm9rdjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnQUNDRVNTX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9ERU5PS1Z9JwogICAgICAtIFNFUlZJQ0VfRlFETl9ERU5PS1ZfNDUxMgogICAgdm9sdW1lczoKICAgICAgLSAnJHtDT09MSUZZX1ZPTFVNRV9BUFB9Oi9kYXRhJwogICAgY29tbWFuZDogJy0tc3FsaXRlLXBhdGggL2RhdGEvZGVub2t2LnNxbGl0ZSBzZXJ2ZSAtLWFjY2Vzcy10b2tlbiAke1NFUlZJQ0VfUEFTU1dPUkRfREVOT0tWfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBuYwogICAgICAgIC0gJy16dicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzQ1MTInCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCg==",
 | 
					        "compose": "c2VydmljZXM6CiAgZGVub2t2OgogICAgaW1hZ2U6ICdnaGNyLmlvL2Rlbm9sYW5kL2Rlbm9rdjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnQUNDRVNTX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9ERU5PS1Z9JwogICAgICAtIFNFUlZJQ0VfRlFETl9ERU5PS1ZfNDUxMgogICAgdm9sdW1lczoKICAgICAgLSAnJHtDT09MSUZZX1ZPTFVNRV9BUFB9Oi9kYXRhJwogICAgY29tbWFuZDogJy0tc3FsaXRlLXBhdGggL2RhdGEvZGVub2t2LnNxbGl0ZSBzZXJ2ZSAtLWFjY2Vzcy10b2tlbiAke1NFUlZJQ0VfUEFTU1dPUkRfREVOT0tWfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBuYwogICAgICAgIC0gJy16dicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzQ1MTInCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCg==",
 | 
				
			||||||
@@ -3083,7 +3083,7 @@
 | 
				
			|||||||
    "unsend": {
 | 
					    "unsend": {
 | 
				
			||||||
        "documentation": "https://docs.unsend.dev/get-started/self-hosting?utm_source=coolify.io",
 | 
					        "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.",
 | 
					        "slogan": "Unsend is an open-source alternative to Resend, Sendgrid, Mailgun and Postmark etc.",
 | 
				
			||||||
        "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1VOU0VORF8zMDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9VTlNFTkR9JwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF82NF9ORVhUQVVUSFNFQ1JFVH0nCiAgICAgIC0gJ0FXU19BQ0NFU1NfS0VZPSR7QVdTX0FDQ0VTU19LRVk6P30nCiAgICAgIC0gJ0FXU19TRUNSRVRfS0VZPSR7QVdTX1NFQ1JFVF9LRVk6P30nCiAgICAgIC0gJ0FXU19ERUZBVUxUX1JFR0lPTj0ke0FXU19ERUZBVUxUX1JFR0lPTjo/fScKICAgICAgLSAnR0lUSFVCX0lEPSR7R0lUSFVCX0lEfScKICAgICAgLSAnR0lUSFVCX1NFQ1JFVD0ke0dJVEhVQl9TRUNSRVR9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9yZWRpczo2Mzc5JwogICAgICAtICdORVhUX1BVQkxJQ19JU19DTE9VRD0ke05FWFRfUFVCTElDX0lTX0NMT1VEOi1mYWxzZX0nCiAgICAgIC0gJ0FQSV9SQVRFX0xJTUlUPSR7QVBJX1JBVEVfTElNSVQ6LTF9JwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtcU8tIGh0dHA6Ly8xMjcuMC4wLjE6MzAwMCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiA1cwogICAgICByZXRyaWVzOiAxMAogICAgICB0aW1lb3V0OiAycwo=",
 | 
					        "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZXhwb3NlOgogICAgICAtIDMwMDAKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9VTlNFTkRfMzAwMAogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtTRVJWSUNFX0RCX1BPU1RHUkVTOi11bnNlbmR9JwogICAgICAtICdORVhUQVVUSF9VUkw9JHtTRVJWSUNFX0ZRRE5fVU5TRU5EfScKICAgICAgLSAnTkVYVEFVVEhfU0VDUkVUPSR7U0VSVklDRV9CQVNFNjRfNjRfTkVYVEFVVEhTRUNSRVR9JwogICAgICAtICdBV1NfQUNDRVNTX0tFWT0ke0FXU19BQ0NFU1NfS0VZOj99JwogICAgICAtICdBV1NfU0VDUkVUX0tFWT0ke0FXU19TRUNSRVRfS0VZOj99JwogICAgICAtICdBV1NfREVGQVVMVF9SRUdJT049JHtBV1NfREVGQVVMVF9SRUdJT046P30nCiAgICAgIC0gJ0dJVEhVQl9JRD0ke0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9TRUNSRVQ9JHtHSVRIVUJfU0VDUkVUfScKICAgICAgLSAnUkVESVNfVVJMPXJlZGlzOi8vcmVkaXM6NjM3OScKICAgICAgLSAnTkVYVF9QVUJMSUNfSVNfQ0xPVUQ9JHtORVhUX1BVQkxJQ19JU19DTE9VRDotZmFsc2V9JwogICAgICAtICdBUElfUkFURV9MSU1JVD0ke0FQSV9SQVRFX0xJTUlUOi0xfScKICAgICAgLSBIT1NUTkFNRT0wLjAuMC4wCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovL3Vuc2VuZDozMDAwIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHRpbWVvdXQ6IDJzCg==",
 | 
				
			||||||
        "tags": [
 | 
					        "tags": [
 | 
				
			||||||
            "resend",
 | 
					            "resend",
 | 
				
			||||||
            "mailer",
 | 
					            "mailer",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "coolify": {
 | 
					    "coolify": {
 | 
				
			||||||
        "v4": {
 | 
					        "v4": {
 | 
				
			||||||
            "version": "4.0.0-beta.409"
 | 
					            "version": "4.0.0-beta.410"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "nightly": {
 | 
					        "nightly": {
 | 
				
			||||||
            "version": "4.0.0-beta.410"
 | 
					            "version": "4.0.0-beta.411"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "helper": {
 | 
					        "helper": {
 | 
				
			||||||
            "version": "1.0.8"
 | 
					            "version": "1.0.8"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user