I cannot promise my solutions will work, but I’ve been confronted to it a few times, and 2 of those cases returned an error like yours.
-
Easiest case: an evil .htaccess that, for some unplanned reason, forbids web access to the path in which the system has briefly stored the temporary file that letsencrypt is seeking.
Solution: replace the .htaccess at the site’s root with a blank file (maybe wait a while, I do not know if htaccess contents are cached or immediately refreshed in the server’s internals.) -
Complicated case: cloudflare interference. If you’re using cloudflare, needless to mention. I had it once, SSL didn’t work anymore because the certificate expired, however cloudflare didn’t care and was still forcing http://path/file requests to be transformed in https://path/file requests, thus making the requests fail every time.
Solution: in the cloudflare panel for that website, entirely disable SSL options, and re-run the certificate creation in virtualmin. Remember to tell come back again to tell cloudflare to use SSL afterwards.