Cloudflare and Heroku: Encrypting End-to-End HTTPS

September 17, 2024
Pete Nicholls
I recently set up a Rails app in Heroku. I wanted Cloudflare to act as a WAF, sitting at the edge and proxying requests to the Heroku app. When I set it up, I got an endless 301 redirect loop. Heres how I solved it.

The redirect loop:

$ curl -i https://my-cool-websiteHTTP/2 301…location: https://my-cool-website/…

Why? It turned out Cloudflare was forwarding the HTTPS request as an HTTP requests to Heroku. My Rails app noticed that the request was not HTTPS, and then issued a redirect to the HTTPS site, resulting in an infinite loop.

After doing some reading, I realised that this behaviour is controlled by Cloudflare’s TLS Custom SSL/TLS settings (under Websites > Website > TLS/SSL). The setting was set to Flexible, which issues your requests as HTTP.

Now this might be suitable for your use case, but I wanted Cloudflare to both handle TLS termination to the client but also make HTTPS requests to Heroku, making it end-to-end encrypted. I tried the Full (Strict) mode, and immediately got this “525 SSL handshake failed” error:

What happened? Even though I had SSL configured on Heroku through Heroku’s Automatic Certificate Management (which uses Let’s Encrypt under the hood), Cloudflare didn’t accept it.

I decided to issue an Origin Server certificate through Cloudflare and install it on Heroku. In Cloudflare, visit Websites > Website > TLS/SSL > Origin Server and generate a certificate.

In Heroku, open your app > Settings > SSL Certificates and add a manual certificate. Copy the public and private keys as prompted.

With that in place, Cloudflare trusts the certificate on the Heroku app and does end-to-end encryption with HTTPS both between Cloudflare and the user and between Cloudflare and the app.

One side-effect of this is that the Cloudflare certificate will not work for the public web. This is probably what you want – nobody should be accessing your Heroku app unless via Cloudflare.

Let’s talk

Contact Us

Stories & insights

read the blog