26

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?

poke
  • 369,085
  • 72
  • 557
  • 602
VSDekar
  • 1,741
  • 2
  • 21
  • 36
  • 1
    In production, its better to use Nginx as frontend, configuring SSL/TLS with nginx is straightforward, you can keep kestrel serving http. Its well-known practice to do ssl-offloading for backend to avoid unnecessary complexity and performance reduction without security impact. MS Azure apply similar architect concept. – Jawad Al Shaikh Oct 11 '17 at 20:24

1 Answers1

38

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);
            });
        }
    }
})
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
poke
  • 369,085
  • 72
  • 557
  • 602
  • Thank you, now i know why i am so confused... could you add some code in your sample which reflects the settings i have made in my `appsettings.json` for https? I would really appreciate that. – VSDekar Sep 21 '17 at 06:57
  • Added (untested) code that should match your configuration. – poke Sep 21 '17 at 07:15
  • 1
    Where are we today on this. Is there an equivalent to the **netsh http add sslcert** command for Kestrel? It currently defaults to the 'localhost' certificate in my machine's store, so there must be a way to change the default thumbprint. – Quark Soup Apr 04 '19 at 15:54
  • @DonaldAirey You can use the configuration with `appsettings.json` that I described above to configure the certificate explicitly. You do not need to use `netsh` since you are not hosting through HTTPsys (so netsh has no effect). – poke Apr 05 '19 at 10:48