Live is streaming live. Watch now.

Infinite HTTPS redirects

For ASP.NET apps that call app.UseHttpsRedirection() / app.UseHsts() in their Startup.cs, you might find that the app responds to HTTPS requests with an infinite HTTP redirect loop when deployed to Kubernetes, especially if you have configured Kubernetes for SSL termination to happen at Kubernetes ingress.

Why? This is because (as is the case for most reverse proxy/load balancer deployments) when the app is deployed on Kubernetes, its Ingress controller takes care of the SSL connection, ie. SSL termination happens on Kubernetes’ Ingress controller, and the app deployed in Kubernetes will be connected to via HTTP, not HTTPS. The app detects that it is being connected to via HTTP, and (rightfully) responds with a redirect to use HTTPS.

What we can do is to indicate to the app that the originating request did indeed use HTTPS. Most reverse proxies/load balancers indicate this by setting the X-Forwarded-For header (contains the IP of the client making the request, ie. the “real” IP) and the X-Forwarded-Proto header (contains the protocol that the client connected via, eg. HTTPS), and Kubernetes Ingress supports this too. Here’s how we can do this:

  1. In your Kubernetes manifest YAML, tell Ingress to set the X-Forwarded-... headers :
- apiVersion: extensions/v1beta1
  kind: Ingress
    name: ...
    namespace: ...
    annotations: ...
      ... "true"
  1. In your app’s Startup.ConfigureServices() (source), tell ASP.NET Core to forward the scheme:
if (string.Equals(
    "true", StringComparison.OrdinalIgnoreCase))
    services.Configure<ForwardedHeadersOptions>(options =>
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | 
        // Only loopback proxies are allowed by default.
        // Clear that restriction because forwarders are enabled by explicit 
        // configuration.
  1. In your Kubernetes manifest YAML, set the environment variable ASPNETCORE_FORWARDEDHEADERS_ENABLED for the app:

          app: ...
        - name: ...
          image: ...
            value: "true"


On This Page