Convert Renewals to DNS via Cloudflare DNS API


#1

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.

Any help would be greatly appreciated.


#2

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:

sudo /usr/local/bin/certbot -a dns-cloudflare -i apache --cert-name example.com --dns-cloudflare-credentials /root/.secrets/cloudflare.ini -d example.com,www.example.com --preferred-challenges dns-01

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).


#3

Thank You, this is perfect!!

Will this command run automatically without user intervention in my crontab for renewals or do I manually have to run it each time?


#4

Hi,

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)

Thank you


#5

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


#6

Right, the fact that it uses DNS now is stored elsewhere (see the files under /etc/letsencrypt/renewal/ if you’re curious).


#7

Perfect. Thank you again for the help!


#8

OK, So I went ahead and tried to do a renewal just to check and I received this error:

root@three:/etc/scripts# cd /etc/letsencrypt/ && ./certbot-auto renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log


Processing /etc/letsencrypt/renewal/three.domain.aero.conf


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)


#9

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.


#10

Ah!!! Good catch…worked with just certbot.

I assume that I do not need to use certbot-auto correct? certbot will still do everything unattended?


#11

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.


#12

I can do that!!

Thanks!


#13

Better yet:

  • When you request the cert, add --renew-hook /etc/init.d/apache2 restart (or better yet, reload rather than restart to perform a graceful reload)
  • In your cron job, use the single command /etc/letsencrypt/certbot-auto renew -q (or whatever the path to certbot is)

#14

Dan -

Thank you. What is the benefit (ie - what does --renew-hook) do for me…?


#15

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").


#16

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.


#17

hummm…ok do I have to add the --renew-hook at the time I make the cert request or can I add that to the renewal config file?

Also, can the --renew-hook point to any script or just the apache script?


#18

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.

renew_hook = /etc/init.d/apache2 reload

It can point to any script.


#19

Got it, does it need to have quote around it as you suggested before?


#20

Or does it hurt just to do another cert request even though I have a current valid cert?