So I have a server with an SSL cert that I did via auto and anto-renew. Works great.
However, we have grown and now I have build a load-balanced set of servers and placed them on Cloudflare utilizing their DNS and load balancing.
I just copied my certs to my various servers and it all works great until it comes time to renew the certificate. In my case, I had to disable all of my load balancing and allow one single server to make the renewal request then copy everything over to the other servers and re-enable my load balancing.
My understand of this is that letencrypt does a DNS lookup and the IP they are getting is the frontend of the load balancers and not my server.
So I understand that you can use certbot with an API directly from Cloudflare that allows the renewal based on certbot being able to add and then delete a DNS record (SEE HERE).
However, I do not know how to convert my renewals from how it works now (Apache Plugin) to the DNS method.
The problem is that the load balancer might pass the request through to the wrong server - i.e., not the one that's running certbot - and that server would be unable to provide the correct response to the challenge.
Type certbot certificates to get a list of your existing certificates and their names. Then run through the procedure to get a new certificate using the DNS authentication method, but when it comes to running the certbot command, add the option: --cert-name existing.cert.name (replacing existing.cert.name with the name of the cert you want to update). This will cause the new cert to replace the old one, including its renewal configuration.
It's also possible to combine the DNS authenticator with the installer from the Apache plugin, so that certbot can use DNS to authenticate but also automatically reload your Apache configuration after renewal. To do this, remove certonly --dns-cloudflare and instead add -a dns-cloudflare -i apache
so the final command would look something like this:
It's also worth noting that if you're using Cloudflare, you have the option of using their Origin CA instead of Let's Encrypt, which might be easier in some circumstances. (Connections from browsers use Cloudflare's certificates, while the certificates on your servers are used only to protect connections coming from Cloudflare itself, so they don't have to be publicly trusted).
If the first time this command is executed successfully, the renewal afterwards should be using cloudflare automatically. (You don't need to change any existing cronjobs / systemd timer setup for certbot renew if this is done correctly)
OK, just to make sure - I run the command you gave me (which ran perfectly, thank you) and I can leave this in my crontab without any changes, correct? I don’t have to tell it DNS or anything:
cd /etc/letsencrypt/ && ./certbot-auto renew && /etc/init.d/apache2 restart
Renewal configuration file /etc/letsencrypt/renewal/three.domain.aero.conf (cert: three.domain.aero) produced >an unexpected error: 'Namespace' object has no attribute 'dns_cloudflare_credentials'. Skipping.
Here is from the logs:
2019-01-04 22:08:04,452:DEBUG:certbot.renewal:Traceback was:
Traceback (most recent call last):
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/renewal.py", line 419, in handle_renewal_request
renewal_candidate = _reconstitute(lineage_config, renewal_file)
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/renewal.py", line 86, in _reconstitute
_restore_plugin_configs(config, renewalparams)
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/renewal.py", line 154, in restore_plugin_configs
if config_item.startswith(plugin_prefix + "") and not cli.set_by_cli(config_item):
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/cli.py", line 219, in set_by_cli
if not isinstance(getattr(detector, var), _Default):
AttributeError: 'Namespace' object has no attribute 'dns_cloudflare_credentials'
2019-01-04 22:08:04,452:DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
File "/opt/eff.org/certbot/venv/bin/letsencrypt", line 11, in
sys.exit(main())
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/main.py", line 1364, in main
return config.func(config, plugins)
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/main.py", line 1271, in renew
renewal.handle_renewal_request(config)
File "/opt/eff.org/certbot/venv/local/lib/python2.7/site-packages/certbot/renewal.py", line 477, in handle_renewal_request
len(renew_failures), len(parse_failures)))
Error: 0 renew failure(s), 1 parse failure(s)
Oh, wait. I just noticed you’re using certbot in one place and certbot-auto in the other. If you used certbot to get the new certificate then you need to use it in the cron job too. Sorry for not spotting that earlier.
The only thing it won’t do is auto-update certbot itself when a new version comes out. That rarely matters, but occasionally it does, so you might want to upgrade it with pip once in a while.
When you run certbot renew, it checks if the cert is due for renewal, and renews it if so - or does nothing if not. If you set it up as Dan suggests, the Apache restart/reload command also only runs when the certificate was renewed, rather than every time the cron job runs. This is useful if you intend to run the cron job frequently (it’s recommended to run it twice daily, so that it has a good chance to recover in the event of a temporary outage).
You still need to use certbot rather than certbot-auto though. Also the command needs to be in quotes if I’m not mistaken (--renew-hook "/etc/init.d/apache2 reload").
In addition to what @jmorahan said, it also further simplifies your cron job, as that only needs the single call to certbot, and the domain’s renewal configuration handles everything else.
It’s recommended to add it when you make the cert request (to avoid accidentally creating an invalid renewal config file), but you can also add it directly to the file if you’re confident that you know what you’re doing.