Sometimes we just need to run kestrel without the need for a green browser padlock and therefor not needing to have a “real” certificate. but still want secure HTTPS communications on the APIs.

Here we will create a simple method you can drop in to generate a valid self-signed certificate on the fly to use in Kestrel on any port of your choice!

In our Program.cs we have the following method where we want to now manually configure Listen Options.

public static IHostBuilder CreateHostBuilder(string[] args) =>
            .ConfigureWebHostDefaults(webBuilder => {
                // Add UseKestrel to control it's options
                .UseKestrel(options => {
                    // http:localhost:5000
                    options.Listen(IPAddress.Loopback, 5000);
                    // https:localhost:5001
                    options.Listen(IPAddress.Loopback, 5001);
                    // http:*:80
                    options.Listen(IPAddress.Any, 80);
                    // https:*:443
                    options.Listen(IPAddress.Any, 443, listenOptions => {

As you can see on line 15 we have a method called GetSelfSignedCertificate() Now we need to add this method to Program.cs or anywhere else you see fit:

private static X509Certificate2 GetSelfSignedCertificate()
  var password = Guid.NewGuid().ToString();
  var commonName = "MyCommonName";
  var rsaKeySize = 2048;
  var years = 5;
  var hashAlgorithm = HashAlgorithmName.SHA256;

  using (var rsa = RSA.Create(rsaKeySize))
    var request = new CertificateRequest($"cn={commonName}", rsa, hashAlgorithm, RSASignaturePadding.Pkcs1);

      new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false)
      new X509EnhancedKeyUsageExtension(
        new OidCollection { new Oid("") }, false)

    var certificate = request.CreateSelfSigned(DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddYears(years));
    certificate.FriendlyName = commonName;

	// Return the PFX exported version that contains the key
    return new X509Certificate2(certificate.Export(X509ContentType.Pfx, password), password, X509KeyStorageFlags.MachineKeySet);

When your application starts up it will enable kestrel to serve on the defined ports and generate a new certificate on the fly and serve your API endpoints securly using HTTPs.

Enjoy 😊


  • Calin says:

    Thank you very much! This is exactly what I was looking for!
    P.S. There is a small mistake in “opt” and “options” variable but is an easy fix.

  • Magnus Sydoff says:

    Thanks Niels for your example.

    I must admit I’ve tried numerous ways to get a local RPI4 (as well as my Win machine) to just present a web page without that annoying initial message from Chrome “Your connection is not private”.

    However, trying your example I still get that. A green padlock would obviously be nice, but just getting rid of that cert is invalid message would be great.

    I’ve tried on Chromium v99 (Chrome and Edge) on my Windows 10 machine using VS2022.
    What can I be doing wrong?

    King regards
    Lund, Sweden

    Subject: MyCommonName

    Issuer: MyCommonName

    Expires on: Mar 22, 2027

    Current date: Mar 22, 2022

    PEM encoded chain:

    • Niels says:

      Hi Magnus,
      Thank you for your comment 🙂

      There is no way unfortunately for you to get a green browser with these certificates, as they are not signed by a CA and are generated on every startup so you cannot even save it to your PC.
      This is meant mostly for scenarios where you either do not have a purchased valid certificate or you are unable to use a service like Let’s Encrypt to generate and renew certificates.
      I personally only use this for API calls where there is no browser warnings but I would like to use SSL. This still means your code has to except “invalid” certificates for it to work.

      Hope this sheds some light on your question.

      Kind regards

  • Patrick says:

    Thank you very much. I was looking for such a solution for a while. I was afraid I had to use an official certificate for my internal app only. This helps a lot!

  • Andrew Bruce says:

    Dude! Thanks so much – I was using ECdsa and I did *something* wrong and kept getting SCHANNEL errors – but your code works like a charm. Much appreciated!

    • Niels says:

      Hi Andrew,
      Thank you so much man I really appreciate you took the time to comment, and I am thrilled it helped you out 🙂

      Good luck with you project

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.