$request->isSecure()]); $domain = $this->deployment->domain(); // Bare-IP mode: no TLS, no host restriction. Keep app.url on the current request // so URLs don't point at a domain that was removed from service. if ($domain === null) { config(['app.url' => $request->getSchemeAndHttpHost()]); return $next($request); } // Internal endpoints must answer on any host/scheme (Caddy's on-demand TLS ask is // a plain-HTTP call with an internal Host; the health check likewise). if ($request->is('_caddy/*', 'up')) { return $next($request); } $host = strtolower($request->getHost()); // The literal server IP is the plaintext recovery path — always served over HTTP. // Pin app.url to the IP request too, so login/onboarding redirects (absolute // route() URLs) stay on the reachable IP instead of bouncing to the (possibly // unreachable) domain that AppServiceProvider set as app.url. if (filter_var($host, FILTER_VALIDATE_IP) !== false) { config(['app.url' => $request->getSchemeAndHttpHost()]); return $next($request); } // Only the active domain may serve the panel by hostname. if ($host !== $domain) { abort(404); } // Force HTTPS for the active domain — on the default TLS port (443). Build the URL // explicitly so a non-standard HTTP APP_PORT is never carried into the https:// URL // (Caddy serves TLS only on 443; https://domain:8080 would be unreachable). // // In external-proxy mode the upstream terminates TLS and owns HTTP->HTTPS; this Caddy is // HTTP-only, so the app must NOT bounce to https://domain:443 (unreachable). The forwarded // scheme still drives cookie-Secure/HSTS above. if (! $this->deployment->externalTls() && ! $request->isSecure()) { return redirect()->to('https://'.$domain.$request->getRequestUri(), 301); } return $next($request); } }