From cb0f2301f5200daee834498bb5196fafc12daabc Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 28 Nov 2025 17:53:26 +0100 Subject: [PATCH] Fix: Traefik proxy startup issues - handle null versions and filter predefined networks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes two critical issues preventing Traefik proxy startup: 1. TypeError when restarting proxy: Handle null return from get_traefik_versions() - Add null check before dispatching CheckTraefikVersionForServerJob - Log warning when version data is unavailable - Prevents: "Argument #2 must be of type array, null given" 2. Docker network error: Filter out predefined Docker networks - Add isDockerPredefinedNetwork() helper to centralize network filtering - Apply filtering in collectDockerNetworksByServer() before operations - Apply filtering in generateDefaultProxyConfiguration() - Prevents: "operation is not permitted on predefined default network" Also: Move $cachedVersionsFile assignment after null check in Proxy.php Tests: Added 7 new unit tests for network filtering function All existing tests pass with no regressions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/Livewire/Server/Navbar.php | 11 ++++++++++- app/Livewire/Server/Proxy.php | 3 +-- bootstrap/helpers/proxy.php | 26 ++++++++++++++++++++---- tests/Unit/ProxyHelperTest.php | 36 ++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/app/Livewire/Server/Navbar.php b/app/Livewire/Server/Navbar.php index 4e3481912..6725e5d0a 100644 --- a/app/Livewire/Server/Navbar.php +++ b/app/Livewire/Server/Navbar.php @@ -10,6 +10,7 @@ use App\Jobs\CheckTraefikVersionForServerJob; use App\Models\Server; use App\Services\ProxyDashboardCacheService; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Illuminate\Support\Facades\Log; use Livewire\Component; class Navbar extends Component @@ -72,7 +73,15 @@ class Navbar extends Component // Check Traefik version after restart to provide immediate feedback if ($this->server->proxyType() === ProxyTypes::TRAEFIK->value) { - CheckTraefikVersionForServerJob::dispatch($this->server, get_traefik_versions()); + $traefikVersions = get_traefik_versions(); + if ($traefikVersions !== null) { + CheckTraefikVersionForServerJob::dispatch($this->server, $traefikVersions); + } else { + Log::warning('Traefik version check skipped: versions.json data unavailable', [ + 'server_id' => $this->server->id, + 'server_name' => $this->server->name, + ]); + } } } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php index 49d872210..bd0590d5e 100644 --- a/app/Livewire/Server/Proxy.php +++ b/app/Livewire/Server/Proxy.php @@ -79,12 +79,11 @@ class Proxy extends Component // Load from global cached helper (Redis + filesystem) $versionsData = get_versions_data(); - $this->cachedVersionsFile = $versionsData; - if (! $versionsData) { return null; } + $this->cachedVersionsFile = $versionsData; $traefikVersions = data_get($versionsData, 'traefik'); return is_array($traefikVersions) ? $traefikVersions : null; diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 6672f8b6f..ac52c0af8 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -6,6 +6,20 @@ use App\Models\Application; use App\Models\Server; use Symfony\Component\Yaml\Yaml; +/** + * Check if a network name is a Docker predefined system network. + * These networks cannot be created, modified, or managed by docker network commands. + * + * @param string $network Network name to check + * @return bool True if it's a predefined network that should be skipped + */ +function isDockerPredefinedNetwork(string $network): bool +{ + // Only filter 'default' and 'host' to match existing codebase patterns + // See: bootstrap/helpers/parsers.php:891, bootstrap/helpers/shared.php:689,748 + return in_array($network, ['default', 'host'], true); +} + function collectProxyDockerNetworksByServer(Server $server) { if (! $server->isFunctional()) { @@ -66,8 +80,12 @@ function collectDockerNetworksByServer(Server $server) $networks->push($network); $allNetworks->push($network); } - $networks = collect($networks)->flatten()->unique(); - $allNetworks = $allNetworks->flatten()->unique(); + $networks = collect($networks)->flatten()->unique()->filter(function ($network) { + return ! isDockerPredefinedNetwork($network); + }); + $allNetworks = $allNetworks->flatten()->unique()->filter(function ($network) { + return ! isDockerPredefinedNetwork($network); + }); if ($server->isSwarm()) { if ($networks->count() === 0) { $networks = collect(['coolify-overlay']); @@ -219,8 +237,8 @@ function generateDefaultProxyConfiguration(Server $server, array $custom_command $array_of_networks = collect([]); $filtered_networks = collect([]); $networks->map(function ($network) use ($array_of_networks, $filtered_networks) { - if ($network === 'host') { - return; // network-scoped alias is supported only for containers in user defined networks + if (isDockerPredefinedNetwork($network)) { + return; // Predefined networks cannot be used in network configuration } $array_of_networks[$network] = [ diff --git a/tests/Unit/ProxyHelperTest.php b/tests/Unit/ProxyHelperTest.php index 563d9df1b..3d5da695c 100644 --- a/tests/Unit/ProxyHelperTest.php +++ b/tests/Unit/ProxyHelperTest.php @@ -153,3 +153,39 @@ it('compares branches for minor upgrades', function () { expect($result)->toBeTrue(); }); + +it('identifies default as predefined network', function () { + expect(isDockerPredefinedNetwork('default'))->toBeTrue(); +}); + +it('identifies host as predefined network', function () { + expect(isDockerPredefinedNetwork('host'))->toBeTrue(); +}); + +it('identifies coolify as not predefined network', function () { + expect(isDockerPredefinedNetwork('coolify'))->toBeFalse(); +}); + +it('identifies coolify-overlay as not predefined network', function () { + expect(isDockerPredefinedNetwork('coolify-overlay'))->toBeFalse(); +}); + +it('identifies custom networks as not predefined', function () { + $customNetworks = ['my-network', 'app-network', 'custom-123']; + + foreach ($customNetworks as $network) { + expect(isDockerPredefinedNetwork($network))->toBeFalse(); + } +}); + +it('identifies bridge as not predefined (per codebase pattern)', function () { + // 'bridge' is technically a Docker predefined network, but existing codebase + // only filters 'default' and 'host', so we maintain consistency + expect(isDockerPredefinedNetwork('bridge'))->toBeFalse(); +}); + +it('identifies none as not predefined (per codebase pattern)', function () { + // 'none' is technically a Docker predefined network, but existing codebase + // only filters 'default' and 'host', so we maintain consistency + expect(isDockerPredefinedNetwork('none'))->toBeFalse(); +});