is( 'terminal/auth', 'terminal/auth/ips', 'api/*', 'webhooks/*' )) { return $next($request); } // Skip host validation if no FQDN is configured (initial setup) $fqdnHost = Cache::get('instance_settings_fqdn_host'); if ($fqdnHost === '' || $fqdnHost === null) { return $next($request); } // For all other routes, use parent's host validation return parent::handle($request, $next); } /** * Get the host patterns that should be trusted. * * @return array */ public function hosts(): array { $trustedHosts = []; // Trust the configured FQDN from InstanceSettings (cached to avoid DB query on every request) // Use empty string as sentinel value instead of null so negative results are cached $fqdnHost = Cache::remember('instance_settings_fqdn_host', 300, function () { try { $settings = InstanceSettings::get(); if ($settings && $settings->fqdn) { $url = Url::fromString($settings->fqdn); $host = $url->getHost(); return $host ?: ''; } } catch (\Exception $e) { // If instance settings table doesn't exist yet (during installation), // return empty string (sentinel) so this result is cached } return ''; }); // Convert sentinel value back to null for consumption $fqdnHost = $fqdnHost !== '' ? $fqdnHost : null; if ($fqdnHost) { $trustedHosts[] = $fqdnHost; } // Trust the APP_URL host itself (not just subdomains) $appUrl = config('app.url'); if ($appUrl) { try { $appUrlHost = parse_url($appUrl, PHP_URL_HOST); if ($appUrlHost && ! in_array($appUrlHost, $trustedHosts, true)) { $trustedHosts[] = $appUrlHost; } } catch (\Exception $e) { // Ignore parse errors } } // Trust all subdomains of APP_URL as fallback $trustedHosts[] = $this->allSubdomainsOfApplicationUrl(); // Always trust loopback addresses so local access works even when FQDN is configured foreach (['localhost', '127.0.0.1', '[::1]'] as $localHost) { if (! in_array($localHost, $trustedHosts, true)) { $trustedHosts[] = $localHost; } } return array_filter($trustedHosts); } }