proxyType(); if ($proxyType === 'NONE') { return 'OK'; } $proxy_configuration = null; if (! $forceRegenerate) { // Primary source: database $proxy_configuration = $server->proxy->get('last_saved_proxy_configuration'); // Validate stored config matches current proxy type if (! empty(trim($proxy_configuration ?? ''))) { if (! $this->configMatchesProxyType($proxyType, $proxy_configuration)) { Log::warning('Stored proxy config does not match current proxy type, will regenerate', [ 'server_id' => $server->id, 'proxy_type' => $proxyType, ]); $proxy_configuration = null; } } // Backfill: existing servers may not have DB config yet — read from disk once if (empty(trim($proxy_configuration ?? ''))) { $proxy_configuration = $this->backfillFromDisk($server); } } // Generate default configuration as last resort if ($forceRegenerate || empty(trim($proxy_configuration ?? ''))) { $custom_commands = []; if (! empty(trim($proxy_configuration ?? ''))) { $custom_commands = extractCustomProxyCommands($server, $proxy_configuration); } Log::warning('Proxy configuration regenerated to defaults', [ 'server_id' => $server->id, 'server_name' => $server->name, 'reason' => $forceRegenerate ? 'force_regenerate' : 'config_not_found', ]); $proxy_configuration = str(generateDefaultProxyConfiguration($server, $custom_commands))->trim()->value(); } if (empty($proxy_configuration)) { throw new \Exception('Could not get or generate proxy configuration'); } ProxyDashboardCacheService::isTraefikDashboardAvailableFromConfiguration($server, $proxy_configuration); return $proxy_configuration; } /** * Check that the stored docker-compose YAML contains the expected service * for the server's current proxy type. Returns false if the config belongs * to a different proxy type (e.g. Traefik config on a CADDY server). */ private function configMatchesProxyType(string $proxyType, string $configuration): bool { try { $yaml = Yaml::parse($configuration); $services = data_get($yaml, 'services', []); return match ($proxyType) { ProxyTypes::TRAEFIK->value => isset($services['traefik']), ProxyTypes::CADDY->value => isset($services['caddy']), ProxyTypes::NGINX->value => isset($services['nginx']), default => true, }; } catch (\Throwable $e) { // If YAML is unparseable, don't block — let the existing flow handle it return true; } } /** * Backfill: read config from disk for servers that predate DB storage. * Stores the result in the database so future reads skip SSH entirely. */ private function backfillFromDisk(Server $server): ?string { $proxy_path = $server->proxyPath(); $result = instant_remote_process([ "mkdir -p $proxy_path", "cat $proxy_path/docker-compose.yml 2>/dev/null", ], $server, false); if (! empty(trim($result ?? ''))) { $server->proxy->last_saved_proxy_configuration = $result; $server->save(); Log::info('Proxy config backfilled to database from disk', [ 'server_id' => $server->id, ]); return $result; } return null; } }