fix(compose): keep port-suffixed SERVICE_URL and SERVICE_FQDN variables in sync with the domain

Closes #9877

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-10-27 17:04:07 +01:00
co-authored by Claude Opus 5.5
parent 1082b598c4
commit 1440ea83d3
7 changed files with 189 additions and 98 deletions
+38
View File
@@ -1,6 +1,7 @@
<?php
use App\Models\Application;
use App\Models\EnvironmentVariable;
use App\Models\Service;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
@@ -675,3 +676,40 @@ function putComposeServiceDomain(
return $domains;
}
/**
* Set the stored SERVICE_URL_ and SERVICE_FQDN_ variables of a compose service from its domain.
* Port variables (SERVICE_URL_API_8000) get the same URL or host with their port appended.
* A null URL and host clear the variables.
*/
function syncComposeServiceUrlVariables(Application $application, string $serviceEnvKey, ?string $url, ?string $host): void
{
if ($url !== null) {
foreach (['URL' => $url, 'FQDN' => $host] as $type => $value) {
$application->environment_variables()->updateOrCreate([
'resourceable_type' => Application::class,
'resourceable_id' => $application->id,
'key' => "SERVICE_{$type}_{$serviceEnvKey}",
], [
'value' => $value,
'is_preview' => false,
]);
}
}
$pattern = '/^SERVICE_(URL|FQDN)_'.preg_quote($serviceEnvKey, '/').'(?:_(\d+))?$/';
$application->environment_variables()
->where(fn ($query) => $query->where('key', 'LIKE', "SERVICE_URL_{$serviceEnvKey}%")
->orWhere('key', 'LIKE', "SERVICE_FQDN_{$serviceEnvKey}%"))
->get()
->each(function (EnvironmentVariable $variable) use ($pattern, $url, $host) {
if (! preg_match($pattern, $variable->key, $matches)) {
return;
}
$value = $matches[1] === 'URL' ? $url : $host;
if ($value !== null && isset($matches[2])) {
$value = "{$value}:{$matches[2]}";
}
$variable->update(['value' => $value]);
});
}
+3 -30
View File
@@ -2034,7 +2034,7 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
if ($resource->build_pack === 'dockercompose') {
foreach ($domains as $forServiceName => $domain) {
$parsedDomain = composeDomainEntryString($domain);
$serviceNameFormatted = str($serviceName)->upper()->replace('-', '_')->replace('.', '_');
$serviceEnvKey = str(normalizeComposeServiceName((string) $forServiceName))->upper()->value();
if (filled($parsedDomain)) {
$parsedDomain = str($parsedDomain)->explode(',')->first();
@@ -2042,42 +2042,15 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
$coolifyScheme = $coolifyUrl->getScheme();
$coolifyFqdn = $coolifyUrl->getHost();
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
$serviceEnvKey = str(normalizeComposeServiceName((string) $forServiceName))->upper();
$coolifyEnvironments->put('SERVICE_URL_'.$serviceEnvKey, $coolifyUrl->__toString());
$coolifyEnvironments->put('SERVICE_FQDN_'.$serviceEnvKey, $coolifyFqdn);
// A preview uses its own domains; the stored variables belong to the main application.
if ($isPullRequest) {
continue;
}
$resource->environment_variables()->updateOrCreate([
'resourceable_type' => Application::class,
'resourceable_id' => $resource->id,
'key' => 'SERVICE_URL_'.$serviceEnvKey,
], [
'value' => $coolifyUrl->__toString(),
'is_preview' => false,
]);
$resource->environment_variables()->updateOrCreate([
'resourceable_type' => Application::class,
'resourceable_id' => $resource->id,
'key' => 'SERVICE_FQDN_'.$serviceEnvKey,
], [
'value' => $coolifyFqdn,
'is_preview' => false,
]);
syncComposeServiceUrlVariables($resource, $serviceEnvKey, $coolifyUrl->__toString(), $coolifyFqdn);
} elseif (! $isPullRequest) {
$resource->environment_variables()->where('resourceable_type', Application::class)
->where('resourceable_id', $resource->id)
->where('key', 'LIKE', "SERVICE_FQDN_{$serviceNameFormatted}%")
->update([
'value' => null,
]);
$resource->environment_variables()->where('resourceable_type', Application::class)
->where('resourceable_id', $resource->id)
->where('key', 'LIKE', "SERVICE_URL_{$serviceNameFormatted}%")
->update([
'value' => null,
]);
syncComposeServiceUrlVariables($resource, $serviceEnvKey, null, null);
}
}
}