diff --git a/CHANGELOG.md b/CHANGELOG.md index d601dcb7d6..711628efb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Fixed - Handle an existing Cloudflare DNS record with a different IP when Coolify adds the DNS record of a new domain automatically. Coolify now replaces the record when it created the record and no other resource uses it. Otherwise it opens the **Configure DNS** dialog, where you can replace the record, and the domain shows the conflict instead of "Not checked" +- Add the Cloudflare DNS record automatically, or open the **Configure DNS** dialog, also when you edit a domain to a hostname in a connected Cloudflare zone, for example when you change a generated domain to your own domain. Before, Coolify did this only when you added a new domain. This applies to the **Domains** pages, the application and service application settings, and the service application API - Save deployments started through the MCP server as MCP deployments, not as API deployments. The deployment list shows them with the **MCP** source and filter, and the API and MCP deployment data have a new `is_mcp` field. The deployments to additional servers keep the source of the main deployment, and the audit log records actions that MCP tools do through the API as MCP events ## [v4.6.0] - 2026-11-02 diff --git a/app/Actions/Service/UpdateServiceApplicationFromApi.php b/app/Actions/Service/UpdateServiceApplicationFromApi.php index dafbc80f30..aa106dc96a 100644 --- a/app/Actions/Service/UpdateServiceApplicationFromApi.php +++ b/app/Actions/Service/UpdateServiceApplicationFromApi.php @@ -4,6 +4,7 @@ namespace App\Actions\Service; use App\Models\ServiceApplication; use App\Services\Dns\ManagedDnsRecordCleanup; +use App\Services\Dns\ResourceDnsRecords; use App\Support\ServiceComposeUrl; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -15,6 +16,7 @@ class UpdateServiceApplicationFromApi $forceDomainOverride = $request->boolean('force_domain_override'); $dnsCleanup = app(ManagedDnsRecordCleanup::class); $previousDnsHostnames = $dnsCleanup->hostnamesOf($serviceApplication->fresh() ?? $serviceApplication); + $previousServiceDnsHostnames = array_keys(app(ResourceDnsRecords::class)->hostnameUsers($serviceApplication->service)); if (array_key_exists('url', $payload)) { $urlRaw = $payload['url']; @@ -135,6 +137,7 @@ class UpdateServiceApplicationFromApi $serviceApplication->save(); $serviceApplication->refresh(); $dnsCleanup->queueReleaseOfRemovedHostnames($serviceApplication, $previousDnsHostnames, (int) $teamId); + app(ResourceDnsRecords::class)->queueAutomaticRecords($serviceApplication->service, $previousServiceDnsHostnames); updateCompose($serviceApplication); diff --git a/app/Livewire/Concerns/InteractsWithDnsProviders.php b/app/Livewire/Concerns/InteractsWithDnsProviders.php index c9022fb03a..d122933067 100644 --- a/app/Livewire/Concerns/InteractsWithDnsProviders.php +++ b/app/Livewire/Concerns/InteractsWithDnsProviders.php @@ -154,6 +154,28 @@ trait InteractsWithDnsProviders return true; } + /** + * Configures DNS for the hostnames that a domain edit added, like configureDnsAfterDomainAdd() does for a new domain. + * + * @param array $urls the URLs of the edit that need a DNS check + * @param array $previousHostnames the hostnames of the resource before the edit + * @return array the URLs that still need a DNS check + */ + protected function configureDnsAfterDomainEdit(array $urls, array $previousHostnames): array + { + $addedUrls = array_values(array_filter($urls, function (string $url) use ($previousHostnames): bool { + $hostname = parse_url($url, PHP_URL_HOST); + + return is_string($hostname) && ! in_array(strtolower($hostname), $previousHostnames, true); + })); + + if ($addedUrls === [] || ! $this->configureDnsAfterDomainAdd($addedUrls)) { + return $urls; + } + + return array_values(array_diff($urls, $addedUrls)); + } + public function openManualDnsRecords(): void { $this->authorizeDnsProviderChange(); diff --git a/app/Livewire/Project/Application/Domains.php b/app/Livewire/Project/Application/Domains.php index 784691a94e..65bfed87ff 100644 --- a/app/Livewire/Project/Application/Domains.php +++ b/app/Livewire/Project/Application/Domains.php @@ -1593,6 +1593,7 @@ class Domains extends Component $this->dispatch('edit-domain-saved'); $this->dispatch('success', 'Domain updated.'); $this->refreshDomains(); + $urlsToCheck = $this->configureDnsAfterDomainEdit($urlsToCheck, $previousDnsHostnames); if ($urlsToCheck !== []) { $this->queueUrlsDns($urlsToCheck, $service); } diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index c7a888a1cd..30689a924e 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -10,6 +10,7 @@ use App\Livewire\Project\Shared\EnvironmentVariable\All; use App\Models\Application; use App\Rules\ValidGitBranch; use App\Services\Dns\ManagedDnsRecordCleanup; +use App\Services\Dns\ResourceDnsRecords; use App\Support\ValidationPatterns; use App\Traits\AuditsApplicationSettings; use Exception; @@ -995,6 +996,7 @@ class General extends Component $this->application->refresh(); $this->dispatch('name-changed', uuid: $this->application->uuid, name: $this->application->name); $dnsCleanup->queueReleaseOfRemovedHostnames($this->application, $previousDnsHostnames, $this->application->team()->id); + app(ResourceDnsRecords::class)->queueAutomaticRecords($this->application, $previousDnsHostnames); $this->syncData(); if ($oldPortsExposes !== $this->application->ports_exposes || $oldCustomNetworkAliases !== $this->application->custom_network_aliases) { $this->dispatch('applicationNetworkingUpdated')->to(InternalAccess::class); diff --git a/app/Livewire/Project/Service/Domains.php b/app/Livewire/Project/Service/Domains.php index 8655730983..dae2642825 100644 --- a/app/Livewire/Project/Service/Domains.php +++ b/app/Livewire/Project/Service/Domains.php @@ -1365,6 +1365,7 @@ class Domains extends Component $this->pendingAction = null; $this->dispatch('success', 'Domain updated.'); $this->refreshDomains(); + $urlsToCheck = $this->configureDnsAfterDomainEdit($urlsToCheck, $previousDnsHostnames); if ($urlsToCheck !== []) { $this->queueUrlsDns($urlsToCheck, $app); } diff --git a/app/Livewire/Project/Service/Index.php b/app/Livewire/Project/Service/Index.php index ed5025ab1b..edfc3c0e97 100644 --- a/app/Livewire/Project/Service/Index.php +++ b/app/Livewire/Project/Service/Index.php @@ -13,6 +13,7 @@ use App\Models\Service; use App\Models\ServiceApplication; use App\Models\ServiceDatabase; use App\Services\Dns\ManagedDnsRecordCleanup; +use App\Services\Dns\ResourceDnsRecords; use App\Support\ValidationPatterns; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Collection; @@ -628,6 +629,7 @@ class Index extends Component try { $persistedApplication = $this->serviceApplication->fresh(); $previousDnsHostnames = app(ManagedDnsRecordCleanup::class)->hostnamesOf($persistedApplication); + $previousServiceDnsHostnames = array_keys(app(ResourceDnsRecords::class)->hostnameUsers($this->service)); $previousEditableUrls = $persistedApplication->url; $previousFqdn = $persistedApplication->fqdn; $previousPortOverrides = $persistedApplication->domain_port_overrides; @@ -687,6 +689,7 @@ class Index extends Component $this->auditServiceSubResourceUpdate($this->serviceApplication, $changedFields); $this->serviceApplication->refresh(); app(ManagedDnsRecordCleanup::class)->queueReleaseOfRemovedHostnames($this->serviceApplication, $previousDnsHostnames, $this->service->team()->id); + app(ResourceDnsRecords::class)->queueAutomaticRecords($this->service, $previousServiceDnsHostnames); $this->syncApplicationData(false); updateCompose($this->serviceApplication); if (str($this->serviceApplication->fqdn)->contains(',')) {