ohadschn/letsencrypt-webapp-renewer

Default webRootPath for linux based webapps is incorrect/undocumented.

profet23 opened this issue · 2 comments

When targeting Linux based asp.net core web apps the default webRootPath puts the .well-known/acme-challenge directory in:

/home/site/wwwroot

When it actually needs to be in:

/home/site/wwwroot/wwwroot

I couldn't get this to work by setting webRootPath to the full path. But by using the following relative path, it seems to be working fine.

./site/wwwroot/wwwroot

Just putting this here to save someone a few hours of debugging and some letsencrypt rate limiting... /sigh

Thank you for the information.

  1. Would you mind submitting a PR to fix the docs?
  2. I suggest you work against the Let's Encrypt staging endpoint to avoid rate limits.

I had a difficult time getting this working for a .NET 5.0 app being deployed to Azure App Service in a Linux container. Posting what I had to do here for anyone else that might come across this.

  1. For the web job set webRootPath to ./acme. This ends up /home/acme. Eg: letsencrypt:appname-webRootPath=./acme
    The guide says to use ./site/wwwroot/wwwroot but both ContentRootPath (./site/wwwroot) and WebRootPath (./site/wwwroot/wwwroot) were ending up as read-only inside the container. /home seems visible and writable.

  2. I added this IApplicationBuilder extension based on Hammad Ahmad's blog:

		private const string WellKnownFolder = ".well-known";
		private const string WellKnownRequestPath = "/.well-known";
		private const string WellKnownContentType = "text/plain";

		/// <summary>
		/// Adds ACME challenge static file support into an application's startup configuration.
		/// </summary>
		/// <param name="builder"><see cref="IApplicationBuilder"/> being configured.</param>
		/// <param name="acmeRootPath">Root folder for ACME challenge files. Default value: <see cref="IWebHostEnvironment.WebRootPath"/>.</param>
		/// <returns>Supplied <see cref="IApplicationBuilder"/> for chaining.</returns>
		public static IApplicationBuilder UseAcmeChallengeStaticFiles(this IApplicationBuilder builder, string? acmeRootPath = null)
		{
			if (builder == null)
				throw new ArgumentNullException(nameof(builder));

			if (string.IsNullOrEmpty(acmeRootPath))
			{
				acmeRootPath = builder.ApplicationServices.GetRequiredService<IWebHostEnvironment>().WebRootPath;
			}

			string acmeChallengeWellKnownFolderPath = $"{acmeRootPath}{Path.DirectorySeparatorChar}{WellKnownFolder}";
			if (!Directory.Exists(acmeChallengeWellKnownFolderPath))
				Directory.CreateDirectory(acmeChallengeWellKnownFolderPath);

			return builder
				.UseStaticFiles(new StaticFileOptions
				{
					RequestPath = WellKnownRequestPath,
					FileProvider = new PhysicalFileProvider(acmeChallengeWellKnownFolderPath),
					ServeUnknownFileTypes = true,
					DefaultContentType = WellKnownContentType
				});
		}
  1. Then register that in startup:
		public void Configure(IApplicationBuilder app, IConfiguration config)
		{
			app.UseAcmeChallengeStaticFiles(config.GetValue<string?>("AcmeChallengeRootFolder", null));
			app.UseStaticFiles();
		}
  1. Hooked up to a config setting for convenience:
{
   "AcmeChallengeRootFolder": "/home/acme",
}

Working for me!