Hi Identity Server 4 team,
I'm currently deploying an Identity Server 4 installation. This is my first foray in to the brave new world of .NET Core, so I read and followed the advice of the .NET Core docs on publishing to a linux production environment which suggests deploying behind an nginx reverse proxy and using it for tasks like SSL termination, since Kestrel isn't built for that.
As a result, the outside world communicates with my installation through https://idsrv and in turn nginx reverse proxies that to http://localhost:5000.
Having looked through the source, unless I've missed something, it appears Identity Server 4 always uses the values in the current HttpContext to create URL's. Thus, although I'm visiting https://idsrv, the discovery document (for example) is sending back http://idsrv/connect/auth.
What would your advice be in this scenario? My solution so far has been to force HTTPS in my nginx config, and to change the scheme in the HttpContext at the start of a request (see below), but this feel really hacky to me.
// Startup.cs
if((new string[]{"production", "staging"}).Contains(env.EnvironmentName))
{
app.Use(ForceSsl);
}
..
private static RequestDelegate ForceSsl(RequestDelegate next)
{
return async ctx => {
ctx.Request.Scheme = "https";
await (next(ctx));
};
}
``
The UseIISIntegration you typically see, like this:
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://localhost:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
basically does the reverse proxy magic when fronting your app with IIS.
Hi Brock,
Is the IISIntegration extension intended to handle reverse proxies generally, or is it specific to IIS? Looking at the source, it seems the latter, but I'm sure I could well be missing something.
I don't know to be honest -- so much changed in that area the months before RTM, and I've not had a chance to re-research it. But when I am using it locally with IIS Express it seems to do some magic to make requests look as if they're from the outside (meaning the host name is corrected, HTTPS is true, etc.).
There is a more generic "reverse proxy headers" middleware - forgot the name. But this is seems to be the recommendation for non-IIS scenarios.
I think it is this one:
https://github.com/aspnet/BasicMiddleware/tree/dev/src/Microsoft.AspNetCore.HttpOverrides
closing - feel free to open a new issue or report back if that works for you.
I have the same problem. I'm using the HttpOverrides to forward the host header (X-Forwarded-Host), but it seems that IdentityServer is ignoring it, because the ./well-known/openid-configuration uses the internal ip and port instead of the forwarded one.
Is there maybe something to be configured on the IdentityServer application to consider those values?
I'm using nginx as reverse proxy.
This is unrelated to identityserver - it is asp.net that must make the translation before calling us.
Put a dummy middleware behind the overrides one and inspect the request. Maybe nginx does not send the right headers.
I also use HttpOverrides and it works correctly for me on self host IdS with nginx in front. I forward X-Forwarded-Host and X-Forwarded-Proto. Maybe problem is in that where you registered HttpOverrides, this middleware must be before UseIdentityServer, because then is registered BaseUrlMiddleware which store host name in the HttpContext.
@sbebrys Can you share some sample (from your code snippet) just to be able to configure here as well ? I have tried this nuget package (HttpOverrides) and have registered before any identityserver use (app.use).
I have my reverse proxy (apache) redirecting /.well-known and /connect endpoints to my docker container running aspnet.core and identityserver.
And when I access https://URL/.well-known/openid-configuration: Issuer is okay (external url) but all the rest is using internal urls
So I just almost figured this out for using nginx as a reverse proxy.
But instead of getting https i get http urls in my discovery document. Any clue how to fix this?
Be sure your nginx configuration looks something like the following:
server {
listen 80;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
additionally add the Microsoft.AspNetCore.HttpOverrides middleware to your application and use it like this (add it before app.UseIdentityServer();):
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
Edit:
Nginx config:
location /api/ {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
Middleware:
var fordwardedHeaderOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
fordwardedHeaderOptions.KnownNetworks.Clear();
fordwardedHeaderOptions.KnownProxies.Clear();
app.UseForwardedHeaders(fordwardedHeaderOptions);
@leastprivilege That's not a solution so it shouldn't be closed.
I just wanted to alternative solution to this one.
Nginx config:
location / {
proxy_http_version 1.1;
proxy_pass http://identityserver;
proxy_set_header Host $host;
}
Startup.cs:
app.Use((context, next) =>
{
if (Environment.GetEnvironmentVariable("SSL_OFFLOAD") == "true")
context.Request.Scheme = "https";
return next();
});
app.UseIdentityServer();
That why you don't need HttpOverrides middleware at all. IdentityServer will read hostname from "Host" header and on environments where you have SSL offload in use you just add environment variable SSL_OFFLOAD=true
@megamindbrian Hopefully this will help with your issue too.
@cblaettl, I used your recomendation, but I get the result without the /api path

Did you also get this behavior?
Edit:
Solved it via nginx configuration
location /api/ {
proxy_pass http://localhost:5010/api/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
dotnet changes in Configure
app.Map("/api", api =>
{
api.UseIdentityServer();
});
For me, this was the key in the latest version (2.2):
services.AddIdentityServer(options =>
{
options.IssuerUri = Configuration["jwt:authority"];
options.PublicOrigin = options.IssuerUri;
});
The PublicOrigin setting is required to change the root URL everywhere (specifically in discovery for bearer tokens). This allows me to host my IdentityServer4 server on the root but then register it somewhere else on my reverse proxy like /openid.
I also use HttpOverrides and it works correctly for me on self host IdS with
nginxin front. I forwardX-Forwarded-HostandX-Forwarded-Proto. Maybe problem is in that where you registeredHttpOverrides, this middleware must be beforeUseIdentityServer, because then is registeredBaseUrlMiddlewarewhich store host name in the HttpContext.
Thank you! I keep forgetting that the middlewares are added in order. I had the middleware _after_ UseIdentityServer. Moved the middleware like you had suggested and it worked!
Hello @kkaung
I readv the comments here and I seen than I have a same problem as you.
I posted my problem on https://stackoverflow.com/questions/54293098/unable-to-call-api-using-my-identity-server-from-a-native-application/54389250#54389250
I had the middleware after UseIdentityServer as you but I always have the message "Internal server error" when I launch the API call.
Could you show me where are my mistakes in my codes?
Thank you!
Hi,
here is the experience that I have made.
Let consider the method:
private void ConfigureHttpsForwardingBehindProxy(IApplicationBuilder app)
{
var fordwardedHeaderOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
fordwardedHeaderOptions.KnownNetworks.Clear();
fordwardedHeaderOptions.KnownProxies.Clear();
app.UseForwardedHeaders(fordwardedHeaderOptions);
}
If you do
...
app.UseIdentityServer();
ConfigureHttpsForwardingBehindProxy(app);
...
Then you will get http but if you do this way
ConfigureHttpsForwardingBehindProxy(app);
app.UseIdentityServer();
Then you become https.
My conclusion is:
1 you need the nginx configuration with minimum
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
2 and this is the most important, the order of applying the code is important
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
So I just almost figured this out for using nginx as a reverse proxy.
But instead of getting https i get http urls in my discovery document. Any clue how to fix this?
Be sure your nginx configuration looks something like the following:
additionally add the
Microsoft.AspNetCore.HttpOverridesmiddleware to your application and use it like this (add it beforeapp.UseIdentityServer();):Edit:
Solution
Nginx config:
Middleware: