I recently received a notification from Netlify that there was a problem renewing the TLS certificate for one of my domains. In this post I discuss why I received that notification, and how I resolved the problem.
My blog is built as a static site, and deployed to Netlify, and I use Cloudflare in front of it as an additional CDN. Now, Netlify generally doesn't need a CDN, as Netlify describe in this post, but I've been happy with Cloudflare in general, and it helps reduce the amount of traffic that hits the Netlify account, so I use it.
Unfortunately, sometimes this setup causes complications.
Netlify automatically configures HTTPS for every website they host to use SSL, using a Lets Encrypt SSL/TLS certificate by default. These certificates have short lifetimes, so Netlify automatically tries to renew the certificate for you.
However, that won't work if you use Cloudflare in front of Netlify. With Cloudflare enabled, it's Cloudflare that handles the HTTPS connection to your browser:
The trouble is, with Cloudflare in front, the Netlify site isn't directly exposed to the internet, so Netlify can't renew the Lets Encrypt certificate. They give you plenty of warning if this happens, by sending the previous email and showing the following in your dashboard.
Now, theoretically, we don't really need HTTPS on the Netlify site. As Troy Hunt discusses in his post “CloudFlare, SSL and unhealthy security absolutism”, the most important thing in apps like my blog is that the final site exposes HTTPS. As I'm using Cloudflare's HTTPS, we've got that covered.
But as far as I can see, Netlify doesn't actually support HTTP, you have to use HTTPS. So what should we do?
That leaves us with a few options:
- Remove Cloudflare entirely. Netlify will be able to renew the certificate.
- Temporarily remove Cloudflare, long enough for Netlify to renew the certificate, then reenable it.
- Manually set a custom SSL/TLS certificate for Netlify, instead of using the automated Lets Encrypt certificate.
Option 1 is kind of avoiding the issue, so I'll ignore it for now. Option 2 is possible, but that means disabling Cloudflare every time Netlify needs to try and provision a certificate. That's not feasible, especially with the (intentionally) short lifetime of Lets Encrypt certificates.
Which brings us to option 3, using a custom certificate. But don't worry, this is nothing like the old days of having to (gasp) buy a certificate. Cloudflare provides certificates for exactly this purpose.
The scenario is that we have Cloudflare in front of our origin server (Netlify), and we want the communication between them to be encrypted with HTTPS. However, only Cloudflare needs to trust the certificate that Netlify uses for HTTPS, which makes things a little easier.
Cloudflare provides origin certificates for exactly this scenario. You can create an origin certificate with Cloudflare, upload it to Netlify, and Netlify will use this certificate for its HTTPS traffic. No need for Netlify to try and renew certificates itself, and we can make the origin certificate long-lived, so we don't have to deal with it for a long time.
Unlike public certificates, which should be short-lived, it feels ok to have an origin cert with a long lifetime. I'm not sure if that's a well-founded gut feeling, but I'm going with it for now!
Let's create the origin certificate on Cloudflare. Login and then go to SSL > Origin Server > Origin Certificates > Create Certificate:
This pops up a modal dialog with a number of options. Don't worry about them too much, we're just going to stick with the defaults for now. Ensure that the domains match the domains you're using in Netlify. I also chose the longest expiry date of 15 years for convenience:
When you click Next, Cloudflare will generate a public and private key pair. The default format is PEM, which is what we need:
Keep this page open, as we'll copy the values to Netlify in a moment.
Login to your Netlify account, and go to Site Settings > Domain management > HTTPS, which shows you the error we saw earlier:
Click on Set Custom Certificate. This opens a page with three text boxes:
The first box is for your PEM public key. Switch back to your Cloudflare tab, and copy the key values to Netlify:
- Copy the value from the top Origin Certificate box on Cloudflare into the Certificate box in Netlify. The value should start with
- Copy the value from the lower Private Key box on Cloudflare into the Private Key box in Netlify. The value should start with
-----BEGIN PRIVATE KEY-----.
Now, Netlify has one more box for the intermediate certificates. I'm not 100% sure if we need this in this case, but I added the Cloudflare root certificate available in this help doc. This value also starts
-----BEGIN CERTIFICATE-----. I used the RSA Root from the help doc when copying to Netlify. Copy this value into the final Intermediate certs on Netlify:
You can now click Install certificate on Netlify, and click OK in Cloudflare. Cloudflare shows the origin certificate in the list, along with a chonky expiry date:
And the HTTPS warnings have now gone from Netlify. The Domains row shows that you're using a CloudFlare Origin Certificate:
And we're done! Hopefully I won't have to do that for another 15 years, but someone else might find it useful! Although it's more effort than the automated certificates from either Netlify or Cloudflare, it certainly beats the old days of having to purchase and install certificates on servers!
In this post I described how to use Cloudflare with Netlify. By default, Netlify tries to use Lets Encrypt to provision HTTPS certificates, but that won't work if you have Cloudflare in front. To work around this, I show how to use Cloudfare to create a custom Origin Certificate and upload this to Netlify. This certificate secures the communication between Netlify and Cloudflare, while Cloudflare continues to provide Lets Encrpyt certificates for the "public facing" leg of your app.