Skip to main content

Getting Correct Scheme, Host, Port Behind a Proxy

When running an API behind a reverse proxy, such as NGINX, the service will not, by default, see the scheme and port of the incoming call.

This is often because the proxy is terminating SSL, and forwarding an http request to your API.

The problem with this is, that your API has no way to correctly compose Urls for redirection, because it doesn't know the scheme and port.

To ensure that your API can see the correct scheme, host, and port, you need to do the following things.

NGINX Config

In the server block of your reverse proxy, verify you have the following three directives:

                # These forward the scheme type (http or https), hostname, and listening port.
                # These are used by the service, when generating redirect urls.
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-Port $server_port;                

Startup.cs

The dotnet service doesn't accept the forwarded headers, by default. So, we need to configure it to accept them.
This is done in the Russian doll logic of your Startup:Configure() routine.

Locate the Configure() of your Startup.cs, and find the UseRouting(); line.
Add the following block after UseRouting():

            // Accept the forwarded headers (scheme, host, port) from NGINX.
            // We do this, because we are running behind a reverse proxy, and don't directly know the scheme and port.
            // So, we have NGINX forward these to us.
            // And, this statement accepts them.
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedProto | 
                                   ForwardedHeaders.XForwardedHost  | 
                                   ForwardedHeaders.XForwardedFor,
                // Important: trust only your proxy
                // options.KnownProxies.Add(IPAddress.Parse("127.0.0.1"));
                // or
                // options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
            });

Usage Logic

Once you have NGINX forwarding the correct scheme, host, and port, and your Startup.cs is accepting it, you can access them like this:

            HttpRequest request = httpContext!.Request;

            // Retrieve the scheme that was forwarded by NGINX...
            // This is set by the following directive in NGINX:
            //  proxy_set_header X-Forwarded-Proto $scheme;
            var scheme = request.Scheme;
            // Retrieve the host that was forwarded by NGINX...
            // This is set by the following directive in NGINX:
            //  proxy_set_header Host $host;
            var hostname = request.Host.Host;
            // Retrieve the port that was forwarded by NGINX...
            // This is set by the following directive in NGINX:
            //  proxy_set_header X-Forwarded-Port $server_port;
            var port = request.Host.Port;