Why doesn't my ASP.NET Core 7 web app launch on HTTPS?

Up until .NET 7, when you use the dotnet run command to run your ASP.NET Core Razor Pages (or MVC) app, the built-in Ketstrel web server would listen on two URLs, one with a http protocol and another that uses the https protocol. This behaviour is documented in many places (including my book) so it might come as a surprise when you run your new .NET 7 app from the command line and it is only available on an http binding. Something changed in .NET 7. What is it and how do you test your .NET 7 web app under https?

A bit of background: if you make a request over HTTPS using a web browser, the browser requires the presence of a trusted HTTPS or TLS cerificate. If there isn't one, the browser refuses to display the content. When you install the .NET SDK, it installs an HTTPS certificate so that you can run your site under HTTPS in a development environment and emulate the production environment as closely as possible - assuming you intend to follow best practice and only make your site available over a secure connection. The problem is that this certificate is not trusted by default. It is not "signed" by a trusted Certificate Authority. So you have to tell your system to trust it by signing it yourself. VS users get a simple prompt when they encounter this issue for the first time but for CLI developers, the experience is different. Trusing the certificate is achieved by executing the following command:

dotnet dev-certs https --trust

.NET is a cross platform framework, and while this process is friction free for Windows and Mac OS users,  those developing on Linux have to perform additional steps depending on their distribution.

The webapp project launch settings that determine which protocol and port to use are stored in a file called launchSettings.json, which is found in the Properties folder of your app. In .NET 6 and earlier, two profiles are created - one that runs on Kestrel, followed by another for running the app on IISExpress. By default, dotnet run uses the first profile it finds. The Kestrel profile contains two bindings - an http one and an https one - assigned to the applicationUrl key. That's why you would typically see log messages confirming that the app was available at two URLs:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:7235
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5235

In .NET 7, the ASP.NET team decided to change the launch settings so that the default behaviour on executing dotnet run (or dotnet watch for hot reload) is to launch the app only on http. This reduces the friction experienced by first time users as they grapple with self-signing certificates, and aligns more with what you see by default with other frameworks. For example, on Node, an Express or Next.Js app usually launches from the command line on http://localhost:3000.

Now the launchSettings file contains three entries in the profiles section. The first (and therefore the default) is named "http" and only has an http binding for the applicationUrl, while the second is named "https" and has two bindings (http and https) just like the default profile in earlier versions.

If you want to run the application under HTTPS, you can select the "https" profile using the --launch-profile (or newly introduced -lp) option from the command line, passing in the name of the "https" profile:

dotnet run --launch-profile https

Then you will revert to the .NET 6 and earlier experience of having the app available at two URLs on different protocols. If you only want to develop under HTTPS and don't want to have to specify which profile to use every time, simply move the https profile above the http profile in the launchSettings file.

Summary

Changes were made to the default HTTPS settings in .NET 7 ASP.NET Core apps to reduce the friction experienced by new adopters of the framework. While this is a good thing, it may lead to some puzzlement among existing developers as they use .NET 7 for the first time from the command line. You can restore the previous behaviour by specifying which launch profile to use when executing dotnet run, or by amending the contents of the launchSettings.json file.