The Problem

TLDR: If you use Azure App Service for Containers - Azure performs HTTPS termination for you. So you can't use Let's Encrypt integration with ASP.NET Core. Jump to the next section for the solution.

Based on several criteria, I decided to run Διαχειριπη in Azure App Service in Container. It is a .NET Core application packaged into docker and deployed.

The next step in the configuration would be to enable HTTPS for the app service, which is done with one control knob unless you need a custom domain. From this moment, things get complicated.

There are two options:

  • Use Azure provided certificates which are paid and pricey 🤑
  • Upload certificate manually

As I don't have a budget to use Azure offered certificates, I need to provide a certificate manually. Fortunately, there is letsencrypt.org service, which lets you provision free certificates.

ASP.NET Core has several libraries which provide integrated and automated certificate provisioning.

But there is another issue ☹. According to the Azure App Service FAQ it handles HTTPS termination. Therefore HTTPS request will never reach application in the container, and certificate will not be used.

Some research led me to this article - https://www.lastcoolnameleft.com/2017/08/letsencrypt-on-azure-app-service-for-linux/

In short, you manually generate a certificate. Pass ACME challenge. And upload the certificate to the Azure Manually.

Solution

Obtaining certificate from Let's Encrypt

Let's Encrypt provides a tool called certbot which can issue certificates.

First of all, you need to install it. Here are the install instructions.

I've used Ubuntu under WSL to get it up and to run.

Then I issued the following command:

sudo certbot certonly --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok -d '*.<domain-name>' -d <domain-name> -m sdiachenko@outlook.com --agree-tos
  • certonly means I need to download a certificate and no additional actions needed
  • --manual - interactive mode
  • --preferred-challenges dns I want to use DNS challenge where I edit DNS TXT records
  • --server https://acme-v02.api.letsencrypt.org/directory ACME directory URI
  • --manual-public-ip-logging-ok allow Public IP logging automatically. Otherwise, it will ask
  • -d '*.<domain-name>' -d <domain-name> I use 2 domains - root and wildcard. Note single quotes around wildcard name.
  • -m sdiachenko@outlook.com I provide my email for important account notifications. Otherwise, I will be asked during creation.
  • --agree-tos accept Terms Of Service automatically.

After the command issued, certbot generated a DNS challenge.

You have to add specific TXT record to your domain.

Important: Wait for it to take effect. I've used this tool to check the status.

Then it will ask to add another duplicate TXT record with the same host but different value.

Let's Encrypt claims that DNS protocol allows it, but my registrar did not let me do it. I tried to replace the previous value with the new one. Waited for changes to take effect and it worked 😊

Success!

- Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/<domain-name>/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/<domain-name>/privkey.pem
   Your cert will expire on 2019-11-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Upload Certificate to Azure

Export PFX certificate:

sudo openssl pkcs12 -export -out myserver.pfx -inkey <path to privkey.pem> -in <path to fullchain.pem file>

Provide password for certificate.

Next step would be to upload it to App Service - it's pretty straightforward and described here.

After associating your custom domain name with the uploaded certificate, you can use HTTPS.

Next Steps: Renewal

Let's Encrypt certificates are valid for 90 days. So I'll have to renew it every once in a while. I'm going to post a follow-up article when I go through the renewal process.

Now I need a way to be reminded about expiration. There is a modern tool with nice free tier which can monitor your certificates.Check Keyhub from Remme.io.
It discovered my new certificate almost instantly, and I'll get an email once expiration is due.