Heroku free Dyno with Cloudflare free SSL

kinopyo avatar

Assume you've configured your Heroku apps to go through Cloudflare, now you want to enable the free SSL on Cloudflare.

On Cloudflare

Go to Cloudflare dashboard. Under the SSL/TLS nav menu, turn on the "Flexible" mode to serve your site over HTTPS.

Cloudflare SSL mode
Cloudflare SSL mode

Then in the Edge Certificates tab, turn on the Always Use HTTPS option to redirect HTTP to HTTPS.

Cloudflare Always Use HTTPS
Cloudflare Always Use HTTPS

Also make sure there is no Certificates configured on Heroku. It should be empty for free Dyno, but if you've downgraded from a paid plan, then there might be leftovers.

Heroku SSL Certificates
Heroku SSL Certificates

At this point your app should run on HTTPS and any HTTP traffic will also be redirected.

On your Rails app

With this configuration, I bumped into this error when I try to submit a form in the Rails app.

HTTP Origin header (https://example.com) didn't match request.base_url (http://example.com)

Can't verify CSRF token authenticity
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)

After a few Google searches, it looks like it's a common problem and I'll need to modify the proxy server to forward the header properly.

Don't know how to do that on Heroku, so I ended up adding a custom middleware as commented in the rails issue . Works like a charm, thanks @tonytonyjan ๐Ÿ‘!

# https://github.com/rails/rails/issues/22965 require "json" class CloudflareProxy def initialize(app) @app = app end def call(env) return @app.call(env) unless env["HTTP_CF_VISITOR"] env["HTTP_X_FORWARDED_PROTO"] = JSON.parse(env["HTTP_CF_VISITOR"])["scheme"] @app.call(env) end end
require "cloudflare_proxy" config.middleware.use CloudflareProxy