<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: John Henderson</title>
    <description>The latest articles on DEV Community by John Henderson (@jhenderson1992).</description>
    <link>https://dev.to/jhenderson1992</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4089356%2F81130d69-bec6-4284-af96-45c6e5c99f29.png</url>
      <title>DEV Community: John Henderson</title>
      <link>https://dev.to/jhenderson1992</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jhenderson1992"/>
    <language>en</language>
    <item>
      <title>AutoHttps: a zero-dependency automatic HTTPS library for ASP.NET Core / Kestrel</title>
      <dc:creator>John Henderson</dc:creator>
      <pubDate>Sun, 06 Sep 2026 14:15:19 +0000</pubDate>
      <link>https://dev.to/jhenderson1992/autohttps-a-zero-dependency-automatic-https-library-for-aspnet-core-kestrel-382j</link>
      <guid>https://dev.to/jhenderson1992/autohttps-a-zero-dependency-automatic-https-library-for-aspnet-core-kestrel-382j</guid>
      <description>&lt;p&gt;Hi. I maintain a library called AutoHttps. It gets a real TLS certificate for your ASP.NET Core app from Let's Encrypt (or any ACME certificate authority) and renews it automatically. You add the package, set three values, and Kestrel serves HTTPS. No external service, and no NuGet dependencies.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;builder.Services.AddAutoHttps(options =&amp;gt;&lt;br&gt;
{&lt;br&gt;
  options.DomainNames.Add("example.com");&lt;br&gt;
  options.EmailAddress = "admin@example.com";&lt;br&gt;
  options.AcceptTermsOfService = true;&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;http-01 and dns-01 challenges, and wildcard certificates through dns-01.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Renews using ACME Renewal Information (RFC 9773), so it follows the schedule the authority asks for and handles short-lived certificates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works with Let's Encrypt, ZeroSSL, Google Trust Services, Buypass, or any ACME directory, including a private or internal CA.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Runs several instances safely, sharing one certificate through a lock.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Serves a self-signed certificate at the very start, until the real one arrives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gives you certificate change and failure callbacks, a health check, metrics, and a way to read the current certificate from code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why it is needed now: LettuceEncrypt, the library most people used for this, was archived in April 2025, and its last release targets .NET 6, which is out of support. At the same time Let's Encrypt is moving to much shorter certificates (six-day ones already exist, and the default is dropping to 45 days), and it now tells clients when to renew through RFC 9773. A client that renews on a fixed 30-day threshold cannot handle either. I could not find a maintained, dependency-free option for Kestrel, so I wrote one.&lt;/p&gt;

&lt;p&gt;How it works: AutoHttps attaches to Kestrel, answers the http-01 challenge directly from your request pipeline (so there is no extra listener to run), writes the certificate and the account key to disk so they survive a restart, and checks for renewal on a timer. If something fails, it keeps serving the certificate it already has and retries, so a certificate problem never takes the app down.&lt;/p&gt;

&lt;p&gt;It targets net8.0 and net10.0, is MIT licensed, and is on NuGet as AutoHttps: &lt;a href="https://www.nuget.org/packages/AutoHttps" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/AutoHttps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source and docs are on GitHub: &lt;a href="https://github.com/astralmaster/AutoHttps" rel="noopener noreferrer"&gt;https://github.com/astralmaster/AutoHttps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it behind a proxy or with several replicas, I would be glad to hear how it goes, since those setups have the most edge cases.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>dotnet</category>
      <category>opensource</category>
      <category>security</category>
    </item>
    <item>
      <title>AutoHttps: automatic HTTPS for ASP.NET Core with no NuGet dependencies</title>
      <dc:creator>John Henderson</dc:creator>
      <pubDate>Mon, 24 Aug 2026 08:11:10 +0000</pubDate>
      <link>https://dev.to/jhenderson1992/autohttps-automatic-https-for-aspnet-core-with-no-nuget-dependencies-43hm</link>
      <guid>https://dev.to/jhenderson1992/autohttps-automatic-https-for-aspnet-core-with-no-nuget-dependencies-43hm</guid>
      <description>&lt;p&gt;I have been building AutoHttps, a small library that gets and renews TLS certificates for an ASP.NET Core app on its own. You add the package, name your domains, and the app obtains a certificate from Let's Encrypt (or any ACME authority) and keeps it renewed. Kestrel serves it. There is nothing to run alongside your process, and no NuGet dependencies come with it.&lt;/p&gt;

&lt;p&gt;Setup&lt;/p&gt;

&lt;p&gt;Three settings:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;builder.Services.AddAutoHttps(options =&amp;gt;&lt;br&gt;
{&lt;br&gt;
    options.DomainNames.Add("example.com");&lt;br&gt;
    options.EmailAddress = "you@example.com";&lt;br&gt;
    options.AcceptTermsOfService = true;&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It wires itself into Kestrel, answers the http-01 challenge from the app's own request pipeline, writes the certificate to disk, and renews it in the background. While AutoHttps waits for the first certificate, it serves a self-signed placeholder, so a fresh connection gets a certificate warning rather than a dropped handshake.&lt;/p&gt;

&lt;p&gt;Why I wrote it&lt;/p&gt;

&lt;p&gt;LettuceEncrypt was the usual answer for this. It was archived in April 2025, and its last release targets .NET 6. On top of that, Let's Encrypt now issues short-lived certificates that last six days, which changes how often you renew and makes a fixed renewal threshold a poor fit. I wanted something current that a service could depend on without pulling in a tree of packages.&lt;/p&gt;

&lt;p&gt;What it does&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;http-01 and dns-01 challenges, with wildcards through dns-01.&lt;/li&gt;
&lt;li&gt;Renewal follows ACME Renewal Information (RFC&amp;nbsp;9773): the authority tells the client when to renew. There is a lifetime-proportional fallback for authorities that do not publish it, which is what lets the six-day certificates renew without extra configuration.&lt;/li&gt;
&lt;li&gt;Certificate profiles, including the shorter lifetimes Let's Encrypt now offers.&lt;/li&gt;
&lt;li&gt;Let's Encrypt, ZeroSSL, Google Trust Services, Buypass, or any ACME directory, with external account binding where the authority requires it.&lt;/li&gt;
&lt;li&gt;Pluggable certificate and account-key storage, a lock for running more than one instance, and a DNS provider interface for dns-01.&lt;/li&gt;
&lt;li&gt;Targets net8.0 and net10.0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Status&lt;/p&gt;

&lt;p&gt;It is new. Point it at the Let's Encrypt staging endpoint while you try it, because production has rate limits. The test suite runs against Pebble, the ACME test server Let's Encrypt maintains, which is a codebase I did not write. I would rather hear that something does not work for your setup than not hear it.&lt;/p&gt;

&lt;p&gt;Links&lt;/p&gt;

&lt;p&gt;NuGet: &lt;a href="https://www.nuget.org/packages/AutoHttps" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/AutoHttps&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/astralmaster/AutoHttps" rel="noopener noreferrer"&gt;https://github.com/astralmaster/AutoHttps&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>dotnet</category>
      <category>security</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Automatic HTTPS on Kestrel in 2026, now that LettuceEncrypt is archived</title>
      <dc:creator>John Henderson</dc:creator>
      <pubDate>Sat, 22 Aug 2026 07:53:07 +0000</pubDate>
      <link>https://dev.to/jhenderson1992/automatic-https-on-kestrel-in-2026-now-that-lettuceencrypt-is-archived-1m3k</link>
      <guid>https://dev.to/jhenderson1992/automatic-https-on-kestrel-in-2026-now-that-lettuceencrypt-is-archived-1m3k</guid>
      <description>&lt;p&gt;If you run an ASP.NET Core app directly on Kestrel, with no nginx or cloud load balancer in front, getting a real TLS certificate has always been the awkward part. For years the answer was LettuceEncrypt, which obtained and renewed a Let's Encrypt certificate inside your app. That project was archived in April 2025, and its last release targets .NET 6. So the question is open again: how do you do this now?&lt;/p&gt;

&lt;p&gt;Two things have changed, and both matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Certificates are getting shorter
&lt;/h2&gt;

&lt;p&gt;Let's Encrypt started issuing six-day certificates this year, and it is taking the default lifetime from 90 days down to 45. The motivation is security, since a leaked key is useful for less time, but the practical effect is that manual renewal is finished. A certificate you rotate by hand, or with a cron job on a fixed schedule, will not keep up. Renewal has to be automatic, and it has to be frequent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Renewal timing is no longer a guess
&lt;/h2&gt;

&lt;p&gt;Alongside the shorter lifetimes, the authority now tells you when to renew. ACME Renewal Information (RFC 9773, published September 2025) hands the client a suggested renewal window. Instead of picking an arbitrary threshold like "renew when 30 days are left," the client asks the CA and follows the window it returns. That also lets the CA spread renewals out so it is not hit by everyone at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that means for a .NET app
&lt;/h2&gt;

&lt;p&gt;You want a client that runs in process, answers the ACME challenge from your own pipeline, and renews on the CA's schedule with no restart. LettuceEncrypt did the first two but never implemented RFC 9773, and it is no longer maintained. FluffySpoon's EncryptWeMust is in a similar state.&lt;/p&gt;

&lt;p&gt;I wrote one for this, AutoHttps (disclosure: I am the author, it is MIT on GitHub). Setup is one call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAutoHttps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DomainNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"example.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"admin@example.com"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AcceptTermsOfService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gets a certificate on first start and keeps it renewed. It answers http-01 from your request pipeline, does dns-01 and wildcards, works with Let's Encrypt or any ACME authority, and has no NuGet dependencies, because the RFC 8555 client is written against the shared framework. For the short-lived certificates above, you opt into the profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Profile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CertificateProfiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShortLived&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The one catch
&lt;/h2&gt;

&lt;p&gt;This only works if Kestrel is the thing terminating TLS. If nginx, IIS, or a load balancer in front holds the certificate, the cert belongs there and an in-process client cannot help. That is the honest boundary: in-process ACME is for the case where your app is the edge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coming from LettuceEncrypt
&lt;/h2&gt;

&lt;p&gt;The APIs are close. DomainNames, EmailAddress, and AcceptTermsOfService keep the same names, so most of a migration is renaming the config section and deleting the UseLettuceEncrypt call. There is a short migration guide in the repo that maps the rest.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/astralmaster/AutoHttps" rel="noopener noreferrer"&gt;https://github.com/astralmaster/AutoHttps&lt;/a&gt;&lt;br&gt;
NuGet: &lt;a href="https://www.nuget.org/packages/AutoHttps" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/AutoHttps&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>aspnet</category>
      <category>tls</category>
      <category>security</category>
    </item>
  </channel>
</rss>
