Skip to content

Azure Functions Support

Simon J.K. Pedersen edited this page Nov 19, 2017 · 2 revisions

Azure Function Support

The site extension is working fine with Azure Functions, since Azure function is running on top of Azure Web apps. For it to work, you however have to create a function that can respond to challenge that lets encrypt uses to validate the ownership of the domain.

Here's how you can do that.

In your function app, create a new proxy for the challenge directory (this is required as the challenge will be a http get to /.well-known/acme-challenge/, and per default a function in a function app will only answer on /api/.

You can setup the proxy in the following way.

Enable proxy

The important setting here is the Route Template: /.well-known/acme-challenge/{*rest} this will match all request that goes to the challenge directory.

All requests that goes here, we want to forward to a function we create for the purpose. This function is in my example hosted at https://%WEBSITE_HOSTNAME%/api/letsencrypt/{rest}

Please note that proxies are a preview feature and you have to enable it, for it to work. You do so under the function app settings. Enable proxy

Next we need to create a function named letsencrypt that will respond with the challenge code.

C#

Create a function using the HttpTrigger-CSharp template, and name it letsencrypt be sure to select anonymous authentication.

Once created paste the following as the functions body

using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, string code, TraceWriter log)
{    
    log.Info($"C# HTTP trigger function processed a request. {code}");

    var content = File.ReadAllText(@"D:\home\site\wwwroot\.well-known\acme-challenge\"+code);
    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content =  new StringContent(content, System.Text.Encoding.UTF8, "text/plain");
    return resp;
}

We need to configure the function to create the code parameter from the request path. So open the integrate tab, and in the route template add the following letsencrypt/{code} Route Template

With the setup, you can use the site-extension as if the function app was any other web app.

Node.js

If you write you functions in node @manuel-guilbault have written a function implementation that you can use

const fs = require('fs');

module.exports = function(context, request) {
  const responseFilePath = `D:\\home\\site\\wwwroot\\.well-known\\acme-challenge\\${context.bindingData.code}`;

  context.log(`Checking for ACME challenge response at '${responseFilePath}'...`);

  fs.exists(responseFilePath, (exists) => {
    if (!exists) {
      context.log(`ACME challenge response file '${responseFilePath}' not found.`);
      context.done(null, {
        status: 404,
        headers: { "Content-Type": "text/plain" },
        body: 'ACME challenge response not found.'
      });
      return;
    }

    context.log(`ACME challenge response file '${responseFilePath}' found. Reading file...`);
    fs.readFile(responseFilePath, (error, data) => {
      if (error) {
        context.log.error(`An error occured while reading file '${responseFilePath}'.`, error);
        context.done(null, { status: 500 });
        return;
      }

      context.log(`ACME challenge response file '${responseFilePath}' read successfully.`);
      context.done(null, {
        status: 200,
        headers: { "Content-Type": "text/plain" },
        body: data
      });
    });
  });
};