Force request host/scheme to App__Domain behind a proxy
The cookie login redirect and other absolute URLs are built from Request.Host; behind a proxy that doesn't forward the Host header that's the internal IP:port, so hitting the domain 302'd to the server IP. Rewrite scheme+host to App__Domain on every request (after UseForwardedHeaders) so all generated URLs stay on the public domain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,4 +26,11 @@ public class AppDomainOptions
|
||||
|
||||
return domain + "/" + path.TrimStart('/');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The configured domain as an absolute base <see cref="Uri"/> (scheme + host [+ port]), or
|
||||
/// <c>null</c> when no domain is set or it can't be parsed.
|
||||
/// </summary>
|
||||
public Uri? GetBaseUri() =>
|
||||
BuildUrl("/") is { } url && Uri.TryCreate(url, UriKind.Absolute, out var uri) ? uri : null;
|
||||
}
|
||||
|
||||
+17
@@ -309,6 +309,23 @@ var app = builder.Build();
|
||||
// Must run before anything that inspects the request scheme/IP (auth, OIDC, cookies).
|
||||
app.UseForwardedHeaders();
|
||||
|
||||
// When App__Domain is set, rewrite every request's scheme + host to the public domain. The
|
||||
// framework builds absolute URLs (the cookie login redirect, the OIDC redirect_uri, …) from
|
||||
// Request.Scheme/Host; behind a proxy that doesn't forward the Host header these are the
|
||||
// internal host (server IP:port), so loading https://<domain>/ would 302 to http://<ip>:8080.
|
||||
// Forcing the host here keeps every generated URL on the public domain. Must run before auth.
|
||||
var publicBaseUri = appDomain.GetBaseUri();
|
||||
if (publicBaseUri is not null)
|
||||
{
|
||||
var publicHost = HostString.FromUriComponent(publicBaseUri);
|
||||
app.Use((context, next) =>
|
||||
{
|
||||
context.Request.Scheme = publicBaseUri.Scheme;
|
||||
context.Request.Host = publicHost;
|
||||
return next(context);
|
||||
});
|
||||
}
|
||||
|
||||
// ── First-run bootstrap ───────────────────────────────────────────────────────
|
||||
// Seed a local admin when no users exist yet, so a plain-HTTP / LAN deployment that
|
||||
// can't use Microsoft OIDC (which requires HTTPS + a matching Entra redirect URI) can
|
||||
|
||||
@@ -46,6 +46,8 @@ These are separate and registered on **different** Entra apps. Don't conflate th
|
||||
|
||||
> **HTTPS note.** The sign-in app is a confidential (Web) client, so Entra requires its `/signin-oidc` redirect URI to be **HTTPS** — plain HTTP is allowed only for `http://localhost`, not a LAN host/IP. To run OIDC on a plain-HTTP LAN deployment, put the app behind an HTTPS-terminating reverse proxy: register `https://your-host/signin-oidc`, and the app honours `X-Forwarded-Proto` (see `UseForwardedHeaders`) to build the correct `https` redirect. Without a proxy, OIDC sign-in won't work over a non-localhost HTTP host — use the local email/password login instead.
|
||||
|
||||
> **Reverse-proxy host.** Set `App__Domain` so the app builds every redirect (cookie login, OIDC) against the public domain regardless of what host the proxy forwards. Without it, a proxy that doesn't forward the `Host` header makes the app 302 to the internal `IP:port` it actually received.
|
||||
|
||||
Persistent state (profiles, settings, templates, logs, exports, certs) lives in `DataFolder`.
|
||||
|
||||
## Installation — Docker (prebuilt image)
|
||||
|
||||
Reference in New Issue
Block a user