fix(deploy): keep preview and build server hosts out of build --add-host

Preview containers (-pr-<id>) came and went with pull requests and
invalidated the build cache of every app on the network. A build server
got the IPs of the deployment server network, which it cannot reach.
Add a per-app setting to turn off network hosts during the build.

Closes #12452

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-11-05 23:34:53 +01:00
co-authored by Claude Opus 5.5
parent 5c34a1b3d4
commit e7e952fcad
10 changed files with 142 additions and 10 deletions
@@ -57,6 +57,7 @@ class ApplicationsController extends Controller
'disable_build_cache',
'inject_build_args_to_dockerfile',
'include_source_commit_in_build',
'include_network_hosts_in_build',
'is_env_sorting_enabled',
'redact_all_env_values_in_logs',
'include_coolify_default_variables',
@@ -90,6 +91,7 @@ class ApplicationsController extends Controller
'disable_build_cache',
'inject_build_args_to_dockerfile',
'include_source_commit_in_build',
'include_network_hosts_in_build',
'is_env_sorting_enabled',
'redact_all_env_values_in_logs',
'include_coolify_default_variables',
@@ -475,6 +477,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
@@ -687,6 +690,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
@@ -899,6 +903,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
@@ -1111,6 +1116,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
@@ -1293,6 +1299,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
@@ -1471,6 +1478,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
@@ -3507,6 +3515,7 @@ class ApplicationsController extends Controller
'disable_build_cache' => ['type' => 'boolean', 'description' => 'Disable the build cache.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean', 'description' => 'Inject build arguments into the Dockerfile build.'],
'include_source_commit_in_build' => ['type' => 'boolean', 'description' => 'Include the source commit in the build.'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts.'],
'is_env_sorting_enabled' => ['type' => 'boolean', 'description' => 'Sort environment variables.'],
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Redact all environment variable values in logs. When false, only locked (shown once) values are redacted. Requires team admin permissions.'],
'include_coolify_default_variables' => ['type' => 'boolean', 'default' => true, 'description' => 'Add the predefined COOLIFY_* variables (COOLIFY_URL, COOLIFY_FQDN, ...) to the environment. Requires team admin permissions. Redeploy to apply it.'],
+28 -10
View File
@@ -366,13 +366,36 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
}
/**
* The --add-host flags for the build, from the containers on the destination network.
*
* A build server gets no flags: the IPs are on the network of the deployment server, so the build
* server cannot reach them, and the flags only invalidate the build cache.
*/
private function networkHostFlags(): string
{
if ($this->use_build_server || ! ($this->application->settings->include_network_hosts_in_build ?? true)) {
return '';
}
$safeNetwork = escapeshellarg($this->destination->network);
$allContainers = instant_remote_process(["docker network inspect {$safeNetwork} -f '{{json .Containers}}' "], $this->server);
if (is_null($allContainers)) {
return '';
}
$allContainers = format_docker_command_output_to_json($allContainers);
return count($allContainers) > 0 ? $this->addHostFlags(collect($allContainers[0])) : '';
}
/**
* Build the --add-host flags for the containers on the destination network.
*
* BuildKit keys every RUN layer on the host names of the --add-host set (not on the IPs), so a
* container that joins or leaves the network between two builds forces a full rebuild. The set
* leaves out the short-lived containers: build helpers (named after their deployment uuid),
* rolling update containers, and the backup and S3 import helpers. It also leaves out the proxy,
* rolling update containers, preview deployments (named `<name>-pr-<id>`, they come and go with
* pull requests), and the backup and S3 import helpers. It also leaves out the proxy,
* Sentinel, and the proxy error page containers: no build uses them, and Coolify recreates them.
*/
private function addHostFlags(Collection $containers): string
@@ -391,6 +414,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
if (isGeneratedContainerName($containerName)) {
continue;
}
if (preg_match('/-pr-\d+$/', (string) $containerName) === 1) {
continue;
}
if ($buildHelperNames->contains($containerName)) {
continue;
}
@@ -454,15 +480,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
try {
// Make sure the private key is stored in the filesystem
$this->server->privateKey->storeInFileSystem();
// Generate custom host<->ip mapping
$safeNetwork = escapeshellarg($this->destination->network);
$allContainers = instant_remote_process(["docker network inspect {$safeNetwork} -f '{{json .Containers}}' "], $this->server);
if (! is_null($allContainers)) {
$allContainers = format_docker_command_output_to_json($allContainers);
$this->addHosts = count($allContainers) > 0 ? $this->addHostFlags(collect($allContainers[0])) : '';
}
if ($this->application->dockerfile_target_build) {
$target = $this->application->dockerfile_target_build;
if (! preg_match(ValidationPatterns::DOCKER_TARGET_PATTERN, $target)) {
@@ -475,6 +492,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
['repository' => $this->customRepository, 'port' => $this->customPort] = $this->application->customRepository();
$this->selectBuildServer();
$this->addHosts = $this->networkHostFlags();
$this->detectBuildKitCapabilities();
$this->decide_what_to_do();
} catch (Exception $e) {
@@ -53,6 +53,9 @@ class Advanced extends Component
#[Validate(['boolean'])]
public bool $includeSourceCommitInBuild = false;
#[Validate(['boolean'])]
public bool $includeNetworkHostsInBuild = true;
#[Validate(['boolean'])]
public bool $isLogDrainEnabled = false;
@@ -148,6 +151,7 @@ class Advanced extends Component
$this->application->settings->disable_build_cache = $this->disableBuildCache;
$this->application->settings->inject_build_args_to_dockerfile = $this->injectBuildArgsToDockerfile;
$this->application->settings->include_source_commit_in_build = $this->includeSourceCommitInBuild;
$this->application->settings->include_network_hosts_in_build = $this->includeNetworkHostsInBuild;
$changedFields = array_keys($this->application->settings->getDirty());
$this->application->settings->save();
$this->auditSettingsUpdate($changedFields);
@@ -178,6 +182,7 @@ class Advanced extends Component
$this->disableBuildCache = $this->application->settings->disable_build_cache;
$this->injectBuildArgsToDockerfile = $this->application->settings->inject_build_args_to_dockerfile ?? true;
$this->includeSourceCommitInBuild = $this->application->settings->include_source_commit_in_build ?? false;
$this->includeNetworkHostsInBuild = $this->application->settings->include_network_hosts_in_build ?? true;
$this->maxRestartCount = $this->application->max_restart_count ?? 0;
}
+3
View File
@@ -51,6 +51,7 @@ use Symfony\Component\Yaml\Yaml;
'redact_all_env_values_in_logs' => ['type' => 'boolean', 'description' => 'Hide every environment variable value in logs. When false, only locked values are hidden.'],
'inject_build_args_to_dockerfile' => ['type' => 'boolean'],
'include_source_commit_in_build' => ['type' => 'boolean'],
'include_network_hosts_in_build' => ['type' => 'boolean', 'description' => 'Add the containers of the destination network as build hosts (--add-host). Turn off to keep the build cache when resources on the network change.'],
'docker_images_to_keep' => ['type' => 'integer'],
'stop_grace_period' => ['type' => 'integer', 'nullable' => true],
'rolling_update_drain_seconds' => ['type' => 'integer', 'description' => 'Seconds to wait after the new container is healthy before old containers stop during a rolling update. 0 turns the wait off.'],
@@ -76,6 +77,7 @@ class ApplicationSetting extends Model
'use_build_secrets' => 'boolean',
'inject_build_args_to_dockerfile' => 'boolean',
'include_source_commit_in_build' => 'boolean',
'include_network_hosts_in_build' => 'boolean',
'is_auto_deploy_enabled' => 'boolean',
'is_force_https_enabled' => 'boolean',
'is_debug_enabled' => 'boolean',
@@ -145,6 +147,7 @@ class ApplicationSetting extends Model
'redact_all_env_values_in_logs',
'inject_build_args_to_dockerfile',
'include_source_commit_in_build',
'include_network_hosts_in_build',
'docker_images_to_keep',
'stop_grace_period',
'rolling_update_drain_seconds',
@@ -176,6 +176,7 @@ class ApplicationConfigurationSnapshot
$this->item('use_build_secrets', 'Use build secrets', data_get($this->application, 'settings.use_build_secrets'), 'build'),
$this->item('inject_build_args_to_dockerfile', 'Inject build args to Dockerfile', data_get($this->application, 'settings.inject_build_args_to_dockerfile'), 'build'),
$this->item('include_source_commit_in_build', 'Include source commit in build', data_get($this->application, 'settings.include_source_commit_in_build'), 'build'),
$this->item('include_network_hosts_in_build', 'Include network hosts in build', data_get($this->application, 'settings.include_network_hosts_in_build'), 'build'),
$this->item('disable_build_cache', 'Disable build cache', data_get($this->application, 'settings.disable_build_cache'), 'build'),
$this->item('is_build_server_enabled', 'Build server', data_get($this->application, 'settings.is_build_server_enabled'), 'build'),
];
+2
View File
@@ -242,6 +242,7 @@ function sharedDataApplications(?Application $application = null): array
'disable_build_cache' => 'boolean',
'inject_build_args_to_dockerfile' => 'boolean',
'include_source_commit_in_build' => 'boolean',
'include_network_hosts_in_build' => 'boolean',
'is_env_sorting_enabled' => 'boolean',
'redact_all_env_values_in_logs' => 'boolean',
'include_coolify_default_variables' => 'boolean',
@@ -522,6 +523,7 @@ function removeUnnecessaryFieldsFromRequest(Request $request)
$request->offsetUnset('is_container_label_escape_enabled');
$request->offsetUnset('is_preserve_repository_enabled');
$request->offsetUnset('include_source_commit_in_build');
$request->offsetUnset('include_network_hosts_in_build');
$request->offsetUnset('is_git_submodules_enabled');
$request->offsetUnset('is_git_lfs_enabled');
$request->offsetUnset('is_git_shallow_clone_enabled');
@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (! Schema::hasColumn('application_settings', 'include_network_hosts_in_build')) {
Schema::table('application_settings', function (Blueprint $table) {
$table->boolean('include_network_hosts_in_build')->default(true)->after('include_source_commit_in_build');
});
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
if (Schema::hasColumn('application_settings', 'include_network_hosts_in_build')) {
Schema::table('application_settings', function (Blueprint $table) {
$table->dropColumn('include_network_hosts_in_build');
});
}
}
};
+32
View File
@@ -846,6 +846,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -1510,6 +1514,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -2174,6 +2182,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -2838,6 +2850,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -3392,6 +3408,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -3926,6 +3946,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -4739,6 +4763,10 @@
"type": "boolean",
"description": "Include the source commit in the build."
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts."
},
"is_env_sorting_enabled": {
"type": "boolean",
"description": "Sort environment variables."
@@ -28214,6 +28242,10 @@
"include_source_commit_in_build": {
"type": "boolean"
},
"include_network_hosts_in_build": {
"type": "boolean",
"description": "Add the containers of the destination network as build hosts (--add-host). Turn off to keep the build cache when resources on the network change."
},
"docker_images_to_keep": {
"type": "integer"
},
+24
View File
@@ -548,6 +548,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -990,6 +993,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -1432,6 +1438,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -1874,6 +1883,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -2253,6 +2265,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -2618,6 +2633,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -3163,6 +3181,9 @@ paths:
include_source_commit_in_build:
type: boolean
description: 'Include the source commit in the build.'
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts.'
is_env_sorting_enabled:
type: boolean
description: 'Sort environment variables.'
@@ -18022,6 +18043,9 @@ components:
type: boolean
include_source_commit_in_build:
type: boolean
include_network_hosts_in_build:
type: boolean
description: 'Add the containers of the destination network as build hosts (--add-host). Turn off to keep the build cache when resources on the network change.'
docker_images_to_keep:
type: integer
stop_grace_period:
@@ -32,6 +32,12 @@
['value' => false, 'label' => 'Runtime only (preserves cache)'],
['value' => true, 'label' => 'Available during build'],
]" :disabled="! $canUpdate" />
<x-forms.listbox id="includeNetworkHostsInBuild" label="Network hosts during build" onChange="instantSave"
helper="When added, the build can reach the containers on the destination network by name. Each time a resource on the network is added or removed, the Docker build cache is invalidated. Preview deployments are never added, and no hosts are added on a build server."
:options="[
['value' => true, 'label' => 'Add network containers as hosts'],
['value' => false, 'label' => 'Do not add (preserves cache)'],
]" :disabled="! $canUpdate" />
</div>
@if ($application->git_based())
<x-application.settings-subsection id="advanced-deployment-section" title="Deployment"