Getting LetsEncrypt certs non-invasively using nginx and webroot
I finally found a nice way to get LetsEncrypt certificates integrated with websites behind a reverse-proxy.
Problem: I don't want certbot messing with my server configs, and I don't want to shut down my main web server just so I can get a cert using --standalone.
The way Nginx interprets location and root directives makes it really easy to solve this problem. Put a location for .well-known into your server config for non-SSL HTTP:
server {
server_name www.example.com;
listen 80;
location / {
rewrite ^(.*) https://$host$1;
}
location /.well-known/ {
root /cert/www.example.com;
}
}
Now:
mkdir -p /cert/www.example.com certbot certonly --webroot -w /cert/www.example.com -d www.example.com
Certbot will now place the credentials somewhere under /cert/www.example.com/.well-known/yadda/IdontKnow, nginx will serve it correctly, authentication will succeed and everyone will live happily ever after. No configuration fiddlements, no shutting down your server, it just freaking works -- and you can totally do that on a reverse proxy without the actual app ever knowing about it.
Update:
I recently had to do it on an Apache2 server. It works similarly, but the Alias directive has to include the .well-known path:
Alias /.well-known /cert/example.com/.well-known
The rest of the procedure works the same way.
Update:
I found that you can even avoid having to define a separate vhost on port 80 for every domain, by using $host in the root statement like so:
server {
server_name www.example.com;
listen 80 default_server;
location / {
rewrite ^(.*) https://$host$1;
}
location /.well-known/ {
root /cert/$host;
}
}
This defines a default server that serves the .well-known paths from the /cert directory, and for everything else, just sends a redirect from http to https. This allows to just grab a cert as soon as DNS resolves, add an SSL-enabled vhost config for the domain, reload and be done.