Skip to content

Commit cb0f230

Browse files
andrasbacsaiclaude
andcommitted
Fix: Traefik proxy startup issues - handle null versions and filter predefined networks
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 <noreply@anthropic.com>
1 parent b246cdf commit cb0f230

File tree

4 files changed

+69
-7
lines changed

4 files changed

+69
-7
lines changed

app/Livewire/Server/Navbar.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use App\Models\Server;
1111
use App\Services\ProxyDashboardCacheService;
1212
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
13+
use Illuminate\Support\Facades\Log;
1314
use Livewire\Component;
1415

1516
class Navbar extends Component
@@ -72,7 +73,15 @@ public function restart()
7273

7374
// Check Traefik version after restart to provide immediate feedback
7475
if ($this->server->proxyType() === ProxyTypes::TRAEFIK->value) {
75-
CheckTraefikVersionForServerJob::dispatch($this->server, get_traefik_versions());
76+
$traefikVersions = get_traefik_versions();
77+
if ($traefikVersions !== null) {
78+
CheckTraefikVersionForServerJob::dispatch($this->server, $traefikVersions);
79+
} else {
80+
Log::warning('Traefik version check skipped: versions.json data unavailable', [
81+
'server_id' => $this->server->id,
82+
'server_name' => $this->server->name,
83+
]);
84+
}
7685
}
7786
} catch (\Throwable $e) {
7887
return handleError($e, $this);

app/Livewire/Server/Proxy.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,11 @@ protected function getTraefikVersions(): ?array
7979

8080
// Load from global cached helper (Redis + filesystem)
8181
$versionsData = get_versions_data();
82-
$this->cachedVersionsFile = $versionsData;
83-
8482
if (! $versionsData) {
8583
return null;
8684
}
8785

86+
$this->cachedVersionsFile = $versionsData;
8887
$traefikVersions = data_get($versionsData, 'traefik');
8988

9089
return is_array($traefikVersions) ? $traefikVersions : null;

bootstrap/helpers/proxy.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@
66
use App\Models\Server;
77
use Symfony\Component\Yaml\Yaml;
88

9+
/**
10+
* Check if a network name is a Docker predefined system network.
11+
* These networks cannot be created, modified, or managed by docker network commands.
12+
*
13+
* @param string $network Network name to check
14+
* @return bool True if it's a predefined network that should be skipped
15+
*/
16+
function isDockerPredefinedNetwork(string $network): bool
17+
{
18+
// Only filter 'default' and 'host' to match existing codebase patterns
19+
// See: bootstrap/helpers/parsers.php:891, bootstrap/helpers/shared.php:689,748
20+
return in_array($network, ['default', 'host'], true);
21+
}
22+
923
function collectProxyDockerNetworksByServer(Server $server)
1024
{
1125
if (! $server->isFunctional()) {
@@ -66,8 +80,12 @@ function collectDockerNetworksByServer(Server $server)
6680
$networks->push($network);
6781
$allNetworks->push($network);
6882
}
69-
$networks = collect($networks)->flatten()->unique();
70-
$allNetworks = $allNetworks->flatten()->unique();
83+
$networks = collect($networks)->flatten()->unique()->filter(function ($network) {
84+
return ! isDockerPredefinedNetwork($network);
85+
});
86+
$allNetworks = $allNetworks->flatten()->unique()->filter(function ($network) {
87+
return ! isDockerPredefinedNetwork($network);
88+
});
7189
if ($server->isSwarm()) {
7290
if ($networks->count() === 0) {
7391
$networks = collect(['coolify-overlay']);
@@ -219,8 +237,8 @@ function generateDefaultProxyConfiguration(Server $server, array $custom_command
219237
$array_of_networks = collect([]);
220238
$filtered_networks = collect([]);
221239
$networks->map(function ($network) use ($array_of_networks, $filtered_networks) {
222-
if ($network === 'host') {
223-
return; // network-scoped alias is supported only for containers in user defined networks
240+
if (isDockerPredefinedNetwork($network)) {
241+
return; // Predefined networks cannot be used in network configuration
224242
}
225243

226244
$array_of_networks[$network] = [

tests/Unit/ProxyHelperTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,39 @@
153153

154154
expect($result)->toBeTrue();
155155
});
156+
157+
it('identifies default as predefined network', function () {
158+
expect(isDockerPredefinedNetwork('default'))->toBeTrue();
159+
});
160+
161+
it('identifies host as predefined network', function () {
162+
expect(isDockerPredefinedNetwork('host'))->toBeTrue();
163+
});
164+
165+
it('identifies coolify as not predefined network', function () {
166+
expect(isDockerPredefinedNetwork('coolify'))->toBeFalse();
167+
});
168+
169+
it('identifies coolify-overlay as not predefined network', function () {
170+
expect(isDockerPredefinedNetwork('coolify-overlay'))->toBeFalse();
171+
});
172+
173+
it('identifies custom networks as not predefined', function () {
174+
$customNetworks = ['my-network', 'app-network', 'custom-123'];
175+
176+
foreach ($customNetworks as $network) {
177+
expect(isDockerPredefinedNetwork($network))->toBeFalse();
178+
}
179+
});
180+
181+
it('identifies bridge as not predefined (per codebase pattern)', function () {
182+
// 'bridge' is technically a Docker predefined network, but existing codebase
183+
// only filters 'default' and 'host', so we maintain consistency
184+
expect(isDockerPredefinedNetwork('bridge'))->toBeFalse();
185+
});
186+
187+
it('identifies none as not predefined (per codebase pattern)', function () {
188+
// 'none' is technically a Docker predefined network, but existing codebase
189+
// only filters 'default' and 'host', so we maintain consistency
190+
expect(isDockerPredefinedNetwork('none'))->toBeFalse();
191+
});

0 commit comments

Comments
 (0)