Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploying behind a reverse proxy #324

Closed
AP-Hunt opened this issue Sep 20, 2016 · 16 comments

Comments

Projects
None yet
@AP-Hunt
Copy link

commented Sep 20, 2016

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));
    };
}
``
@brockallen

This comment has been minimized.

Copy link
Member

commented Sep 20, 2016

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.

@brockallen brockallen added the question label Sep 20, 2016

@AP-Hunt

This comment has been minimized.

Copy link
Author

commented Sep 20, 2016

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.

@brockallen

This comment has been minimized.

Copy link
Member

commented Sep 20, 2016

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.).

@leastprivilege

This comment has been minimized.

Copy link
Member

commented Sep 23, 2016

There is a more generic "reverse proxy headers" middleware - forgot the name. But this is seems to be the recommendation for non-IIS scenarios.

@leastprivilege

This comment has been minimized.

Copy link
Member

commented Sep 23, 2016

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.

@fleed

This comment has been minimized.

Copy link

commented Nov 1, 2016

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.

@leastprivilege

This comment has been minimized.

Copy link
Member

commented Nov 1, 2016

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.

@sbebrys

This comment has been minimized.

Copy link

commented Nov 1, 2016

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.

@brunobertechini

This comment has been minimized.

Copy link

commented Apr 7, 2017

@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

@cblaettl

This comment has been minimized.

Copy link

commented Jun 16, 2017

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:

Solution

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);
@megamindbrian

This comment has been minimized.

Copy link

commented Aug 10, 2017

@leastprivilege That's not a solution so it shouldn't be closed.

@olljanat

This comment has been minimized.

Copy link

commented Aug 22, 2017

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.

@timdows

This comment has been minimized.

Copy link

commented Oct 8, 2017

@cblaettl, I used your recomendation, but I get the result without the /api path

2017-10-08 12_04_52

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();
    });

@HeyJoel HeyJoel referenced this issue Apr 6, 2018

Closed

Login w/ HTTPS #195

@douglampe

This comment has been minimized.

Copy link

commented May 25, 2018

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.

@kkaung

This comment has been minimized.

Copy link

commented Dec 11, 2018

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.

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!

@Sylade

This comment has been minimized.

Copy link

commented Jan 29, 2019

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.