fix(domains): limit instance addresses to localhost DNS hints

This commit is contained in:
Andras Bacsai 2026-09-04 20:56:08 +02:00
parent dba3d114e5
commit 9c3fb1da39
5 changed files with 100 additions and 12 deletions

View file

@ -209,19 +209,20 @@ protected function serverIpsForDnsHints(): array
}
}
// Prefer instance public IPv6 when the destination IP is IPv4-only (and vice versa).
try {
$settings = instanceSettings();
$publicV4 = data_get($settings, 'public_ipv4');
$publicV6 = data_get($settings, 'public_ipv6');
if ($ipv4 === null && is_string($publicV4) && filter_var($publicV4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$ipv4 = $publicV4;
if ($this->usesInstanceNetworkAddressesForDnsHints()) {
try {
$settings = instanceSettings();
$publicV4 = data_get($settings, 'public_ipv4');
$publicV6 = data_get($settings, 'public_ipv6');
if ($ipv4 === null && is_string($publicV4) && filter_var($publicV4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$ipv4 = $publicV4;
}
if ($ipv6 === null && is_string($publicV6) && filter_var($publicV6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$ipv6 = $publicV6;
}
} catch (\Throwable) {
//
}
if ($ipv6 === null && is_string($publicV6) && filter_var($publicV6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$ipv6 = $publicV6;
}
} catch (\Throwable) {
//
}
return [$ipv4, $ipv6];
@ -253,5 +254,7 @@ protected function serverIpForDomainConnect(): ?string
return null;
}
abstract protected function usesInstanceNetworkAddressesForDnsHints(): bool;
abstract protected function authorizeUpdateForDomainConnect(): void;
}

View file

@ -661,6 +661,11 @@ protected function authorizeUpdateForDomainConnect(): void
$this->authorize('update', $this->application);
}
protected function usesInstanceNetworkAddressesForDnsHints(): bool
{
return $this->application->destination?->server?->id === 0;
}
public function checkAllDns(): void
{
$this->authorize('update', $this->application);

View file

@ -459,6 +459,11 @@ protected function authorizeUpdateForDomainConnect(): void
$this->authorize('update', $this->service);
}
protected function usesInstanceNetworkAddressesForDnsHints(): bool
{
return $this->service->server?->id === 0;
}
public function checkAllDns(): void
{
$this->authorize('update', $this->service);

View file

@ -716,6 +716,63 @@
->not->toContain('app.example.com');
});
it('does not use instance network addresses for dns entries on a remote server', function () {
InstanceSettings::get()->update([
'public_ipv4' => '198.51.100.20',
'public_ipv6' => '2001:db8::20',
]);
$this->application->update(['fqdn' => 'https://app.example.com']);
$component = Livewire::test(Domains::class, ['application' => $this->application->fresh()]);
$records = $component->instance()->dnsRecordHints();
expect($records)->toBe([
[
'type' => 'A',
'name' => 'app.example.com',
'value' => '203.0.113.10',
],
]);
});
it('uses instance network addresses for dns entries on the localhost server', function () {
InstanceSettings::get()->update([
'public_ipv4' => '198.51.100.20',
'public_ipv6' => '2001:db8::20',
]);
$localhost = Server::factory()->create([
'id' => 0,
'team_id' => $this->team->id,
'private_key_id' => $this->server->private_key_id,
'ip' => 'localhost',
]);
$destination = StandaloneDocker::withoutEvents(fn () => StandaloneDocker::forceCreate([
'uuid' => (string) Str::uuid(),
'name' => 'localhost-docker',
'network' => 'coolify-localhost',
'server_id' => $localhost->id,
]));
$this->application->update([
'destination_id' => $destination->id,
'fqdn' => 'https://app.example.com',
]);
$component = Livewire::test(Domains::class, ['application' => $this->application->fresh()]);
expect($component->instance()->dnsRecordHints())->toBe([
[
'type' => 'A',
'name' => 'app.example.com',
'value' => '198.51.100.20',
],
[
'type' => 'AAAA',
'name' => 'app.example.com',
'value' => '2001:db8::20',
],
]);
});
it('shows cloudflare domain connect only on cloud with a key', function () {
config([
'constants.coolify.self_hosted' => false,

View file

@ -280,6 +280,24 @@
->not->toContain('web.example.com');
});
it('does not use instance network addresses for service dns entries on a remote server', function () {
InstanceSettings::get()->update([
'public_ipv4' => '198.51.100.20',
'public_ipv6' => '2001:db8::20',
]);
$this->apiApp->update(['fqdn' => 'https://api.example.com']);
$component = Livewire::test(Domains::class, ['service' => $this->service->fresh(['applications', 'server'])]);
expect($component->instance()->dnsRecordHints())->toBe([
[
'type' => 'A',
'name' => 'api.example.com',
'value' => '203.0.113.10',
],
]);
});
it('persists a service redirect when its dropdown changes', function () {
$this->webApp->update(['fqdn' => 'https://web.example.com', 'redirect' => 'both']);