I have an application with Nginx docker container for which the TLS certs are generated manually using the following command in the host (with Ubuntu OS) where application is deployed:
certbot certonly --manual --manual-public-ip-logging-ok --preferred-challenges dns -d my.app.com
When the certificates gets expired, i have to renew them.
But i can’t use the following certbot renew
command for this purpose as it will give an error:
$ sudo certbot renew
Failed to renew certificate my.app.com with error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')
So, what I’m doing now is to create the certs once again (using the same certbot certonly
command that was used previously) instead of renewing them.
How can I fix the error with certbot renew
command?
How can I automate this setup?
2
Answers
Here is my setup. It involves the LE secrets living in a docker volume that is shared between nginx and certbot, and nginx proxying the renewal requests to certbot, so you do not have to stop nginx while certbot does its validation.
nginx setup
proxy LE verififcation to certbot backend
Requests on port 80 to letsencrypt validation are forwarded to certbot, anything else gets redirecte to https.
(In case you are wondering why I define the proxy pass backend as a variable, see this SO answer)
SSL setup
pretty much standard stuff here:
docker-compose magic
certbot
Have a special "docker-compose-LE.yml" to single run certbot:
By running "docker-compose -f docker-compose-LE.yml up" you will create and validate a certificate. You can use the same command to renew the certificate, certbot is that smart. You may run this command as often as you like (daily), because it will only renew your certificate when it is about to expire.
See "caveat" below before running this command the first time.
nginx
in docker-compose.yml mount the certificates from a volume. That volume has already been created by letsencrypt, so declare it as external.
caveat
This method causes a chicken-egg-problem when creating the certifivate the first time: Without a cert file nginx won’t start and can’t proxy the LE validation. No nginx means no certificate, and no certificate means no nginx.
To get around this you have to do the very first call of certbot without nginx and using certbots internal http server exposed. So the first time you run certbot add these lines to docker-compose-LE.yml:
cert renewal
Simply run these two command in a daily cronjob:
Will check the certificate and start renewal process once it is due. The now running nginx will proxy the certification validation to certbot.
Once the certificate is updated inplace inside the docker volume certbot and nginx are sharing, simply send a SIGHUP to nginx so it reloads the cert files without interrupting service.
I needed to use an ‘external’ network to allow the containers from the two docker-compose files to communicate. Thanks for this!