HTTPS – Fix Certbot Connection Refused While /.well-known/acme-challenge is Accessible

Apache2httpslets-encrypt

I'm having issues to renew my certificate for my Nextcloud instance with letsencrypt on my ubuntu 16.04 server.

Here is my renewal conf:

  # renew_before_expiry = 30 days
version = 0.22.2
archive_dir = /etc/letsencrypt/archive/cloud.example.com
cert = /etc/letsencrypt/live/cloud.example.com/cert.pem
privkey = /etc/letsencrypt/live/cloud.example.com/privkey.pem
chain = /etc/letsencrypt/live/cloud.example.com/chain.pem
fullchain = /etc/letsencrypt/live/cloud.example.com/fullchain.pem

# Options used in the renewal process
[renewalparams]
post_hook = service apache2 start
installer = apache
account = a57eab015444b60984498d853e6c3531
authenticator = webroot
rsa_key_size = 4096
pre_hook = service apache2 stop
#server = https://acme-v02.api.letsencrypt.org/directory

[[webroot_map]]
cloud.example.com = /var/www/nextcloud/

My apache virtualhost:

<VirtualHost *:80>
    ServerName cloud.example.com
  DocumentRoot /var/www/nextcloud

<Location />
   Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
    Satisfy Any

 </Location>

        <Location /.well-known/>
        DirectoryIndex index.html
        DirectoryIndex enabled
        Require all granted
        </Location>

RedirectMatch 301 ^(?!/\.well-known/acme-challenge/).* https://cloud.example.com$0

</VirtualHost>

Output whilst performing certbot renew

Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator webroot, Installer apache
Running pre-hook command: service apache2 stop
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for cloud.example.com
Waiting for verification...
Cleaning up challenges
Attempting to renew cert (cloud.example.com) from /etc/letsencrypt/renewal/cloud.example.com.conf produced an unexpected error: Failed authorization procedure. cloud.example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://cloud.example.com/.well-known/acme-challenge/fFCxCpEYRDWwBY0PMgAVljisoVdnc5wer6TblEA5pk8: Connection refused. Skipping.

This is what I get when executing curl -I http://cloud.example.be/.well-known/acme-challenge/

HTTP/1.1 200 OK
Date: Tue, 14 Aug 2018 12:37:55 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Tue, 14 Aug 2018 11:06:06 GMT
ETag: "6-5736332475bab"
Accept-Ranges: bytes
Content-Length: 6
Content-Type: text/html

So the http -> https redirection (see apache config) is doing its job except for directory /.well-known/acme-challenge so certbot can verify over port 80.

What else could be wrong to get this error message please?

update:
here is output from /var/log/letsencrypt/letsencrypt.log

2018-08-16 08:26:44,196:DEBUG:certbot.reporter:Reporting to user: The following errors were reported by the server:

Domain: cloud.example.com
Type:   connection
Detail: Fetching http://cloud.example.com/.well-known/acme-challenge/aDaOaVPP0x21mngx_pYAdLUhPRp6gTT0wxHgs5kIwqA: Connection refused

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. Additionally, please check that your computer has a publicly routable IP address and that no firewalls are preventing the server from communicating with the client. If you're using the webroot plugin, you should also verify that you are serving files from the webroot path you provided.
2018-08-16 08:26:44,197:DEBUG:certbot.error_handler:Encountered exception:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/certbot/auth_handler.py", line 82, in handle_authorizations
    self._respond(aauthzrs, resp, best_effort)
  File "/usr/lib/python3/dist-packages/certbot/auth_handler.py", line 155, in _respond
    self._poll_challenges(aauthzrs, chall_update, best_effort)
  File "/usr/lib/python3/dist-packages/certbot/auth_handler.py", line 226, in _poll_challenges
    raise errors.FailedChallenges(all_failed_achalls)
certbot.errors.FailedChallenges: Failed authorization procedure. cloud.example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://cloud.example.com/.well-known/acme-challenge/aDaOaVPP0x21mngx_pYAdLUhPRp6gTT0wxHgs5kIwqA: Connection refused

2018-08-16 08:26:44,197:DEBUG:certbot.error_handler:Calling registered functions
2018-08-16 08:26:44,197:INFO:certbot.auth_handler:Cleaning up challenges
2018-08-16 08:26:44,198:DEBUG:certbot.plugins.webroot:Removing /var/www/nextcloud/.well-known/acme-challenge/aDaOaVPP0x21mngx_pYAdLUhPRp6gTT0wxHgs5kIwqA
2018-08-16 08:26:44,198:DEBUG:certbot.plugins.webroot:All challenges cleaned up
2018-08-16 08:26:44,198:WARNING:certbot.renewal:Attempting to renew cert (cloud.example.com) from /etc/letsencrypt/renewal/cloud.example.com.conf produced an unexpected error: Failed authorization procedure. cloud.example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://cloud.example.com/.well-known/acme-challenge/aDaOaVPP0x21mngx_pYAdLUhPRp6gTT0wxHgs5kIwqA: Connection refused. Skipping.
2018-08-16 08:26:44,200:DEBUG:certbot.renewal:Traceback was:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 430, in handle_renewal_request
    main.renew_cert(lineage_config, plugins, renewal_candidate)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1197, in renew_cert
    renewed_lineage = _get_and_save_cert(le_client, config, lineage=lineage)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 115, in _get_and_save_cert
    renewal.renew_cert(config, domains, le_client, lineage)
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 305, in renew_cert
    new_cert, new_chain, new_key, _ = le_client.obtain_certificate(domains, new_key)
  File "/usr/lib/python3/dist-packages/certbot/client.py", line 334, in obtain_certificate
    orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names)
  File "/usr/lib/python3/dist-packages/certbot/client.py", line 370, in _get_order_and_authorizations
    authzr = self.auth_handler.handle_authorizations(orderr, best_effort)
  File "/usr/lib/python3/dist-packages/certbot/auth_handler.py", line 82, in handle_authorizations
    self._respond(aauthzrs, resp, best_effort)
  File "/usr/lib/python3/dist-packages/certbot/auth_handler.py", line 155, in _respond
    self._poll_challenges(aauthzrs, chall_update, best_effort)
  File "/usr/lib/python3/dist-packages/certbot/auth_handler.py", line 226, in _poll_challenges
    raise errors.FailedChallenges(all_failed_achalls)
certbot.errors.FailedChallenges: Failed authorization procedure. cloud.example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://cloud.example.com/.well-known/acme-challenge/aDaOaVPP0x21mngx_pYAdLUhPRp6gTT0wxHgs5kIwqA: Connection refused

2018-08-16 08:26:44,211:INFO:certbot.renewal:Cert not yet due for renewal
2018-08-16 08:26:44,213:DEBUG:certbot.plugins.selection:Requested authenticator webroot and installer apache
2018-08-16 08:26:44,213:DEBUG:certbot.plugins.selection:Selecting plugin: * apache
Description: Apache Web Server plugin - Beta
Interfaces: IAuthenticator, IInstaller, IPlugin
Entry point: apache = certbot_apache.entrypoint:ENTRYPOINT
Initialized: <certbot_apache.override_debian.DebianConfigurator object at 0x7f1ced56be10>
2018-08-16 08:26:44,214:ERROR:certbot.renewal:All renewal attempts failed. The following certs could not be renewed:
2018-08-16 08:26:44,214:ERROR:certbot.renewal:  /etc/letsencrypt/live/cloud.example.com/fullchain.pem (failure)
2018-08-16 08:26:44,215:INFO:certbot.hooks:Running post-hook command: service apache2 start
2018-08-16 08:26:45,610:DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
  File "/usr/bin/certbot", line 11, in <module>
    load_entry_point('certbot==0.26.1', 'console_scripts', 'certbot')()
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1364, in main
    return config.func(config, plugins)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1276, in renew
    renewal.handle_renewal_request(config)
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 455, in handle_renewal_request
    len(renew_failures), len(parse_failures)))
certbot.errors.Error: 1 renew failure(s), 0 parse failure(s)

Best Answer

It seems like you have a conflict in your configuration...

The certbot output

 Plugins selected: Authenticator webroot, Installer apache

and the debug output:

2018-08-16 08:26:44,213:DEBUG:certbot.plugins.selection:Requested authenticator webroot and installer apache  
2018-08-16 08:26:44,213:DEBUG:certbot.plugins.selection:Selecting plugin: * apache

show that it then tries to do a renewal request using the webroot. The webroot plugin works by creating a temporary file for each of your requested domains in ${webroot-path}/.well-known/acme-challenge. Then the Let’s Encrypt validation server makes HTTP requests to validate that the DNS for each requested domain resolves to the server running certbot.

Of course that won't work when your web server is not running during the renewal process...

Running pre-hook command: service apache2 stop

is the likely reason you see a connection refused.

The debug event after the failed renewal:

2018-08-16 08:26:44,215:INFO:certbot.hooks:Running post-hook command: service apache2 start

is the reason why manually checking the status of your webserver does work, apache gets restarted.

Try what happens when you comment out the pre-hook stopping of apache (and changing the post-hook to service apache2 restart)