Recently I have been playing around with Blazor Web Assembly and decided to publish a little side project I have been working on. As always, there are several things which you need to consider when you go from working on a project just on your local machine to publishing it for the world to see. One of the most tedious of these tasks is getting an HTTPS certificate for your site.
Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit. It is a free way to get HTTPS certificates for your site! The problem is, there is no built in support for Let's Encrypt in Microsoft Azure.
Currently, the easiest way to get Let's Encrypt working with Azure is using the Let's Encrypt Site Extension. I am so glad this extension exists because I am not sure if this is a process I would want to do manually. For the most part, this extension worked for me - until it came time for the certificate to be issued and a challenge url was sent to my site. I am not sure if it was the blazor routing, .net core 5, or just something specific about my site but I could not get the url which looks like:
to return the correct response. From looking at the site extension code it is supposed to work like this:
- A plain text file is created in your blob storage container (which you have previously registered with the plugin) with the file name maching the challenge id in the url and its contents with the challenge code which is supposed to be returned to Let's Encrypt.
- When the request comes into the challenge url, the plugin will serve up the contents of the file from blob storage
Like I mentioned, this was not working for me and my site was returning a 404 for the challenge url.
The solution I finally came up with was to write my own asp.net middleware to serve up the file from blob storage.
public class AcmeChallengeMiddleware
private readonly RequestDelegate next;
private readonly IConfiguration configuration;
private readonly BlobServiceClient client;
private readonly string containerName;
public AcmeChallengeMiddleware(RequestDelegate next, IConfiguration configuration)
this.next = next ?? throw new ArgumentNullException(nameof(next));
this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
string connectionString = this.configuration["letsencrypt:AuthorizationChallengeBlobStorageAccount"];
this.client = new BlobServiceClient(connectionString);
this.containerName = this.configuration["letsencrypt:AuthorizationChallengeBlobStorageContainer"];
public async Task InvokeAsync(HttpContext context)
if (context.Request.Path.Value.Contains("acme-challenge", StringComparison.OrdinalIgnoreCase))
var key = context.Request.Path.Value.Split('/').Last();
BlobContainerClient containerClient = this.client.GetBlobContainerClient(this.containerName);
BlobClient blobClient = containerClient.GetBlobClient(".well-known/acme-challenge/" + key);
var blob = await blobClient.DownloadAsync();
using (var memoryStream = new MemoryStream())
text = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
This class uses the already configured values for the blob storage account used by the Let's Encrypt Plugin. This is a quick and dirty solution that worked for me.
To use this middleware in your asp.net core site, you can add this class to your project and register the class in your
I hope this helps unblock somebody else in the same situation I found myself in.