-
Notifications
You must be signed in to change notification settings - Fork 76
Azure Functions 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.
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.
Next we need to create a function named letsencrypt
that will respond with the challenge code.
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}
With the setup, you can use the site-extension as if the function app was any other web app.
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
});
});
});
};