The client lacks sufficient authorization whilst renewing a Let’s Encrypt certificate on a Virtualmin server

Background

This is a complex issue and the interplay between various technologies such as DNS, HTTP Challenge, website (Apache / NGINX), permissions, and redirections can make the problem incredibly hard to troubleshoot.

Tips

Carefully evaluate the error. Specifically looks for the `Invalid response from` string as you might be getting a completely different reply that you would expect.

Original Article with Amendments

On a Virtualmin server, refreshing a Let’s Encrypt certificate gives the error. We have highlighted in bold the note to watch for in the output as there could be many different failed outcomes for Let’s Encrypt, e.g.

  • 404
  • Unauthorized

This log file covers Unauthorized

Requesting a certificate for domain.com from Let's Encrypt ..
.. request failed : Web-based validation failed :

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Cert is due for renewal, auto-renewing...
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for domain.com
Using the webroot path /home/domain.com/public_html for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Failed authorization procedure. domain.com (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://domain.com/.well-known/acme-challenge/A3oiNXYoxM6Bwze9iTWC0KoxCf-JzF49ozlwJpVzucc [52.215.112.96]: "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-w"
IMPORTANT NOTES:
- The following errors were reported by the server:

Domain: domain.com
Type: unauthorized
Detail: Invalid response from
http://domain.com/.well-known/acme-challenge/A3oiNXYoxM6Bwze9iTWC0KoxCf-JzF49ozlwJpVzucc
[x.y.112.96]: "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n
<meta charset=\"utf-8\">\n <meta name=\"viewport\"
content=\"width=device-w"

To fix these errors, please make sure that your domain name was
entered correctly and the DNS A/AAAA record(s) for that domain
contain(s) the right IP address.

The error was because the NGINX file had directives that wouldn’t let Let’s Encrypt complete. A radical approach worked by refreshing the NGINX configuration but Edit Virtual Server, remove NGINX and SSL NGINX and then re-add. However, the next time this happened another path was chosen:

Revert to Certbot when all else fails

For this specific instance Certbot was chosen instead. One possible reason why Certbot might work better from the command line is this:

Using the webroot path /home/domain.com/public_html for all unmatched domains.

If you’ve modified your webroot, which is often the case for a YII or Laravel application, that path will not be valid anymore.

So instead of using the UI, we used the following command logged in as Root:

sudo certbot --nginx -d domainname.com

To get Certbot to automatically renew, see this article:

https://certbot.eff.org/docs/using.html?highlight=renew#automated-renewals

How Virtualmin’s Let’s Encrypt HTTP Challenge Works

To gain understanding of Let’s Encrypt’s algorithm, it’s broadly like this:

  1. Trigger a new SSL install
  2. The source server receives the challenge and write a temporary file
  3. Web server contacts the Let’s Encrypt Server to initiate request
  4. Let’s Encrypt connects back to the source server to see if the challenge is valid find the temporary file
  5. If point 4 succeed, request is successful

Where if normally fails is point 4, for whatever reason. The biggest noob mistake is no DNS record pointing to the source server, and then using something such a Cloudflare also needs special treatment because Cloudflare intercepts DNS.

What about Well Known stuff?

Let’s Encrypt HTTP Challenge likes to write to local disk. In that case this should be there:

location ~ /\.(?!well-known).* {
        deny all;
    }

Missing index.php

It was a Laravel website, so I also had to add both:

index index.html index.php

and

location / {
   try_files $uri $uri/ /index.php?$query_string;
}

to get the site running.

I believe the location parameter broke the well known location. This error is hard to troubleshoot, see multiple references all with different answers below:

References

If you are still having problems with Let’s Encrypt and Virtual, contact us on 27 82 309-6710 to sort out.

Share this article

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top