Motivation
I have got quite a few domains that I use for different things. Typically, most up to all of them should have valid TLS certificates. Now in an earlier post, I wrote down how generate wildcard certificates, using the DNS challenge. Still, it is sometimes useful to have the “normal” HTTP challenge. Now I wanted to achive that, without having acme.sh on more than one host - I wanted to manage all my certificates on one server.
The challenge was: I have got multiple exposed hosts that are running different services. Some HTTP challenges should be handled on one server, while others had to be handled on another one. I had to find a way around that.
A word on security
Distributing TLS certificates can be dangerous, as the private key should typically not be given away. In my case, this is not too hard - as on all these virtual machines, I am the only person who has shell access to it. Additionally, most of them are only available on my local network.
Setup nginx
The solution was surprisingly simple: When requesting a HTTP challenge for subdomain.tech-tales.blog
then Let’s encrypt expects a specific file to be found in http://subdomain.tech-tales.blog/.well-known/acme-challenge/something
. So let’s just redirect this path to my certificate server!
I updated my default nginx configuration as follows:
server {
listen 80 default_server;
listen [::]:80 default_server;
# ...
location /.well-known/acme-challenge/ {
proxy_pass http://ip.of.cert.server/.well-known/acme-challenge/;
}
}
Before, I just redirected every HTTP request to HTTPS. Newly, this is still the case - unless the request is something in /.well-known/acme-challenge/
; this one will be forwarded to my certificate server.
The certificate server got a similar setup:
server {
listen 80;
server_name ip.of.cert.server;
root /var/www/acme-http;
}
Setup acme.sh
Now the certificate server, or to be more precise, acme.sh
, just has to be told where to put the challenge file. This also was not too hard:
acme.sh --issue --server letsencrypt_test -d subdomain.tech-tales.blog --webroot /var/www/acme-http/
That way, the following happens:
acme.sh
issues a TLS certificate forsubdomain.tech-tales.blog
.- It is told to use
/var/www/acme-http/
as webroot. acme.sh
receives a challenge file from Let’s encrypt and places it in/var/www/acme-http/.well-known/acme-challenge/something
.- Let’s encrypt requests
http://subdomain.tech-tales.blog/.well-known/acme-challenge/something
. This is first responded by nginx on my cloud server and reverse proxied to my certificate server. The certificate server finds the file placed byacme.sh
and delivers it. - Let’s Encrypt is happy and I get my certificate!
- Note: Now the certificate still has to be deployed back to the cloud server! I will write about this in another post.
Conclusion
I like the concept of having all TLS certificates stored on one server, as I don’t loose the overview that way. And with this setup, I can combine both HTTP and DNS challenge.