Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Let's Encrypt Failing DVSNI Challenge

I'm trying to configure Let's Encrypt certificates on a server that is publically accessible. Originally, the server was hiding behind a router, but I have since forwarded ports 80 and 443.

The certificate seems to have completed a majority of the install process, but fails with the message: Failed to connect to host for DVSNI challenge.

Full stack trace:

Updating letsencrypt and virtual environment dependencies......
    Requesting root privileges to run with virtualenv: sudo /bin/letsencrypt certonly --standalone -d example.net -d www.example.net
    Failed authorization procedure. example.net (tls-sni-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Failed to connect to host for DVSNI challenge

IMPORTANT NOTES:
 - The following 'urn:acme:error:connection' errors were reported by
   the server:

   Domains: example.net
   Error: The server could not connect to the client to verify the
   domain

Any support would be greatly appreciated!

I looked around elsewhere for a solution and haven't had much luck. Most other similar situations were resolved by forwarding port 443, but I am certain this port is already forwarded and open, albeit no service is currently running on it.

It shouldn't make a difference, but I'm trying to configure this certificate for use with Node JS on a Raspberry Pi.

like image 389
James Taylor Avatar asked Jan 08 '16 08:01

James Taylor


People also ask

Why shouldn't you use lets encrypt?

Why shouldn't you use Let's Encrypt? The biggest issue is that, although Let's Encrypt provides the modern standard of website encryption, it doesn't offer Extended Domain Validation (the green bar beside the URL, displaying the company name next to the padlock).

Can I renew an expired LetsEncrypt certificate?

Renewing the LetsEncrypt certificate using the certbot Obtain a browser-trusted certificate and set it up on your web server. Keep track of when your certificate is going to expire, and renew it. Help you revoke the certificate if that ever becomes necessary. Renew the certificate forcefully if the need arises.

What is well known Acme challenge?

The ACME CA challenges the client to host a random number at a random URL under /. well-known/acme-challenge on port 80. The CA verifies client control by issuing an HTTP GET request to that URL.

Why is LetsEncrypt only 90 days?

Let's Encrypt issues certificates valid for 90 days. The reason given is that these certificates "limit damage from key compromise and mis-issuance" and encourage automation.


2 Answers

I finally figured out what was going on. I discovered that the --manual flag steps through the authentication process interactively.

Each phase in the process will display a prompt similar to the following:

Make sure your web server displays the following content at
http://www.example.net/.well-known/acme-challenge/twJCKQm9SbPEapgHpyU5TdAR1ErRaiCyxEB5zhhw0w8 before continuing:

twJCKQm9SbPEapgHpyU5TdAR1ErRaiCyxEB5zhhw0w8.t7J7DDTbktMGCCu2KREoIHv1zwkvwGfJTAkJrnELb4U

If you don't have HTTP server configured, you can run the following
command on the target server (as root):

mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge
cd /tmp/letsencrypt/public_html
printf "%s" twJCKQm9SbPEapgHpyU5TdAR1ErRaiCyxEB5zhhw0w8.t7J7DDTbktMGCCu2KREoIHv1zwkvwGfJTAkJrnELb4U > .well-known/acme-challenge/twJCKQm9SbPEapgHpyU5TdAR1ErRaiCyxEB5zhhw0w8
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"

Press ENTER to continue

As I discovered, the process, despite being run as root itself, did not have the privileges to start the challenge server itself. Surely, this might be a bug in the API.

Running the script in the prompt directly produces the following error:

$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
> "import BaseHTTPServer, SimpleHTTPServer; \
> s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
> s.serve_forever()"

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python2.7/SocketServer.py", line 419, in __init__
    self.server_bind()
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 108, in server_bind
    SocketServer.TCPServer.server_bind(self)
  File "/usr/lib/python2.7/SocketServer.py", line 430, in server_bind
    self.socket.bind(self.server_address)
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 13] Permission denied

But running it as root (as the prompt itself stated) started the server correctly and could be monitored as the external server queried it to complete the challenge:

sudo $(command -v python2 || command -v python2.7 || command -v python2.6) -c "import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"

66.133.109.36 - - [08/Jan/2016 21:25:10] "GET /.well-known/acme-challenge/SZ88SorxBGXBtSZCTn4FX2g7u5XjnPFOOV3f5S5DuXB HTTP/1.1" 200 -
66.133.109.36 - - [08/Jan/2016 21:25:10] "GET /.well-known/acme-challenge/twJCKQm9SbPEapgHpyU5TdAR1ErRaiCyxEB5zhhw0w8 HTTP/1.1" 200 -

This error took awhile to diagnose as many things could have prevented the challenges from failing and the servers spawned were failing silently in the background.

like image 177
James Taylor Avatar answered Oct 14 '22 05:10

James Taylor


If you're using Cloudflare DNS in front of your site, remember to have the DNS A, AAAA records point directly to your site, temporarily until renewal finishes.

like image 37
Jeff Tsay Avatar answered Oct 14 '22 04:10

Jeff Tsay