TL;DR What is today the correct way to setup HTTPS with ASP.NET Core 2.0?
I would like to configure my project to use https and a certificate like they have shown at BUILD 2017. I have tried several settings but nothing worked. After some research, I am even more confused. It seems that there are many ways to configure URLs and ports… I have seen appsettings.json
, hosting.json
, via code, and in launchsettings.json
we can also set the URL and port.
Is there a "standard" way to do it?
Here is my appsettings.development.json
{
"Kestrel": {
"Endpoints": {
"Localhost": {
"Address": "127.0.0.1",
"Port": "40000"
},
"LocalhostWithHttps": {
"Address": "127.0.0.1",
"Port": "40001",
"Certificate": {
"HTTPS": {
"Source": "Store",
"StoreLocation": "LocalMachine",
"StoreName": "My",
"Subject": "CN=localhost",
"AllowInvalid": true
}
}
}
}
}
}
But it always takes the url and the port from launchsettings.json
when I start from the command line with dotnet run
or when I start with the debugger from Visual Studio.
This is my Program.cs
and Startup.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
public class Startup
{
public IConfiguration Configuration { get; }
public string Authority { get; set; } = "Authority";
public string ClientId { get; set; } = "ClientId";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MvcOptions>(options => options.Filters.Add(new RequireHttpsAttribute()));
JsonConvert.DefaultSettings = () => new JsonSerializerSettings() {
NullValueHandling = NullValueHandling.Ignore
};
services.AddSingleton<IRepository, AzureSqlRepository>(x => new AzureSqlRepository(Configuration.GetConnectionString("DefaultConnection")));
services.AddSingleton<ISearchSplitService, SearchSplitService>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => new JwtBearerOptions {
Authority = this.Authority,
Audience = this.ClientId
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions() { HotModuleReplacement = true, ReactHotModuleReplacement = true, HotModuleReplacementEndpoint = "/dist/__webpack_hmr" });
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
}
As I have said, I was not able to get it working in any constallation. What is today the correct way to setup HTTPS with ASP.NET Core 2.0?
Unfortunately, the way of configuration-based way of setting up HTTPS that has been shown in various videos or tutorials before the launch of ASP.NET Core 2.0 didn’t make it into the final release.
For 2.0, the only way to configure HTTPS is in code, by explicitly setting up the Kestrel listeners, as explained in this announcement, and using ListenOptions.UseHttps
to enable HTTPS:
var host = new WebHostBuilder()
.UseKestrel(options =>
{
options.ListenAnyIP(443, listenOptions =>
{
listenOptions.UseHttps("server.pfx", "password");
});
})
.UseStartup<Startup>()
.Build();
Unfortunately, at the time of release, the official documentation also did not cover this properly and advertised the configuration-based way that wasn’t implemented. This has been fixed since.
Starting with ASP.NET Core 2.1, configuration based HTTPS setup will be possible, as originally promised. This will likely look like this, as explained by Tratcher on GitHub:
"Kestrel": {
"Endpoints": {
"HTTPS": {
"Url": "https://*:443",
"Certificate": {
"Path": "server.pfx",
"Password": "password"
}
}
}
}
In your particular example, the code-based configuration would look like the following. Note that if you don’t want to use a certificate file, you need to manually retrieve the certificate from the certificate store first.
.UseKestrel(options =>
{
// listen for HTTP
options.ListenLocalhost(40000);
// retrieve certificate from store
using (var store = new X509Store(StoreName.My))
{
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindBySubjectName,
"localhost", false);
if (certs.Count > 0)
{
var certificate = certs[0];
// listen for HTTPS
options.ListenLocalhost(40001, listenOptions =>
{
listenOptions.UseHttps(certificate);
});
}
}
})