March 1, 2016 · ssl servers

Proxying letsencrypt acme-challenge requests


Let’s Encrypt is cool enough. But I personally run into problem with fqdn verification, letsencrypt client should be invoked from the same ip that domain has.

So if u wanna ssl certificate for example.org (which obviously has ipv4 address 93.184.216.34) but want generate certificate(s) from some another server letsencrypt.example.org (e.g. micro aws instance or so with ip 93.184.216.32) you out of luck. There are several workarounds explicitly described in rfc. But they can't be automated easily, moreover certificates issued for 90 days, so automation is a good choice here.

But, if you own your servers or have access to server/application configs - there are elegant solution. We need just proxying letsencrypt acme-challenge request from example.org to that server where letsencrypt run's and use webroot native plugin (standalone is also usable, but not flexible at all).

In a nutshell:

Let’s Encrypt service want receive acme-challenge from example.org, it make request to unique address (hash) after /.well-known/acme-challenge/ path. So when example.org/example.org/.well-known/acme-challenge/{$hash} has correct hash path and value - certificate will be issued.

Process is something like this:

#letsencrypt client sends to letsencrypt service dns, hash and value
1) letsencrypt.example.org -> letsencrypt service [example.org & $hash & $value]  
#letsencrypt service make request and obtain value (if so)
2) letsencrypt service -> example.org/.well-known/acme-challenge/{$hash}  
#and if all is ok
3) letsencrypt service -> letsencrypt.example.org <storing key and certificate>  

Example from http://letsencrypt.readthedocs.org/:

66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"  

First of all, we need to specify webroot plugin, authenticator (used for certonly) and acme-challenge location for letsencrypt client:

./letsencrypt-auto certonly -w /opt/ssl/example.org --authenticator webroot --email bob@example.org -d example.org

In this case letsencrypt client will write verification file to /opt/ssl/example.org and tell letsencrypt service to make verification request.

Now, just one simple change in example.org server config (nginx in my case):

location  "/.well-known/acme-challenge/" {  
    proxy_pass http://letsencrypt.example.org;  
}

Ok, all acme-challenge requests now goeing to letsencrypt.example.org.

letsencrypt service -> example.org/.well-known/acme-challenge/{$hash} -> letsencrypt.example.org  

And now we just need to serve acme-challenge hash file using favorite method (nginx, Node, Python, netcat :D). For testing, python one-liner will be enough:

cd /opt/ssl/example.org && python -m "SimpleHTTPServer" 80  

Ok, cool:

IMPORTANT NOTES:  
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.org/fullchain.pem. Your cert
   will expire on 2016-06-03. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - If you like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

That method is extremely easy to configure and automate, for receiving certificates from dozen different domains using one letsencrypt endpoint.

Note: letsencrypt has a limit (around 5) for certificates per week.

Cheers :)

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket
Comments powered by Disqus