HTTPS is non-negotiable for any production web application โ it encrypts all traffic between clients and the server, preventing eavesdropping, man-in-the-middle attacks, and credential theft. ASP.NET Core has first-class HTTPS support: Kestrel (the built-in web server) handles TLS termination directly, a single middleware call enforces HTTPS redirects, and HSTS headers tell browsers to never connect over HTTP. Understanding how to configure HTTPS correctly for development, Docker, and production environments is foundational infrastructure knowledge for the Web API chapters.
HTTPS Configuration in ASP.NET Core
// โโ Program.cs โ HTTPS middleware setup โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
var app = builder.Build();
// UseHsts โ adds Strict-Transport-Security header (production only)
// Tells browsers: only connect via HTTPS for the next 1 year
// Do NOT enable in Development โ breaks localhost HTTP development tooling
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
// UseHttpsRedirection โ redirects HTTP to HTTPS with 307 Temporary Redirect
// In production, use 301 Permanent Redirect (configured via options)
app.UseHttpsRedirection();
// โโ Configure HSTS in Program.cs build phase โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
builder.Services.AddHsts(options =>
{
options.Preload = true; // include in HSTS preload list
options.IncludeSubDomains = true; // apply to all subdomains
options.MaxAge = TimeSpan.FromDays(365); // 1 year
options.ExcludedHosts.Add("localhost"); // never HSTS on localhost
});
// โโ Configure HTTPS redirection โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 443;
});
max-age). Once a browser receives the HSTS header, it will refuse HTTP connections for that duration โ even if the user types http://. The Preload option submits your domain to browser-maintained HSTS preload lists (embedded in Chrome, Firefox, Edge), meaning browsers enforce HTTPS even on the very first visit, before receiving the HSTS header. HSTS preloading is essentially irreversible โ only apply it when you are certain HTTPS will be maintained permanently.dotnet dev-certs https --trust to create and trust a self-signed development certificate. This certificate is stored in the user’s certificate store and trusted by the OS, allowing HTTPS to work without browser warnings on localhost. On CI/CD pipelines, set the ASPNETCORE_Kestrel__Certificates__Default__Path and ASPNETCORE_Kestrel__Certificates__Default__Password environment variables to provide the certificate. For production, use a certificate from Let’s Encrypt, your cloud provider’s certificate management service, or a commercial CA.X-Forwarded-Proto header: app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto }). Without this, HTTPS redirects loop infinitely because Kestrel thinks the request is HTTP.Kestrel HTTPS Configuration
// โโ appsettings.json โ Kestrel HTTPS endpoint โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// {
// "Kestrel": {
// "Endpoints": {
// "Http": {
// "Url": "http://*:80"
// },
// "Https": {
// "Url": "https://*:443",
// "Certificate": {
// "Path": "/certs/blogapp.pfx",
// "Password": "REPLACE_WITH_CERT_PASSWORD"
// }
// }
// }
// }
// }
// โโ Programmatic Kestrel HTTPS configuration โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(System.Net.IPAddress.Any, 443, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
// Load certificate from Azure Key Vault
httpsOptions.ServerCertificateSelector = (context, name) =>
LoadCertificateFromVault(name);
});
});
});
Reverse Proxy with Forwarded Headers
// โโ Behind Nginx/load balancer: forward original scheme and IP โโโโโโโโโโโโโ
// Must be BEFORE UseHttpsRedirection to prevent redirect loops!
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor
| ForwardedHeaders.XForwardedProto;
// Trust only your specific proxy โ do not use KnownAnyNetwork in production!
options.KnownProxies.Add(System.Net.IPAddress.Parse("10.0.0.1"));
});
// In pipeline โ FIRST middleware, before UseHsts and UseHttpsRedirection
app.UseForwardedHeaders();
app.UseHsts();
app.UseHttpsRedirection();
Common Mistakes
Mistake 1 โ Using UseHsts in Development (breaks localhost tooling)
โ Wrong โ HSTS forces HTTPS on localhost, breaking HTTP development tools and test runners.
โ
Correct โ wrap with if (!app.Environment.IsDevelopment()).
Mistake 2 โ Not configuring ForwardedHeaders behind a reverse proxy (infinite redirect loop)
โ Wrong โ Kestrel sees HTTP request, redirects to HTTPS, proxy forwards as HTTP again, infinite loop.
โ Correct โ configure ForwardedHeaders to trust the proxy and read X-Forwarded-Proto before UseHttpsRedirection.