Asher Cohen
Back to posts

Next JS - How to handle SSL on Heroku —  The Good, the Bad and the Ugly

Guide on handling SSL/HTTPS in React/Next.js apps deployed on Heroku, including redirect issues and middleware solutions.

Clint Eastwood, Lee Van Cleef, Eli Wallach Clint Eastwood as “the Good”, Lee Van Cleef as “the Bad”, and Eli Wallach as “the Ugly”

So you’ve deployed a website on Heroku and now you would like to serve it with SSL encryption as every good tutorial teaches you.

Easy, you think, Heroku manages this pretty well from the dashboard (https://devcenter.heroku.com/articles/ssl) but what if your customers try to access the website with a normal http url?

Say your website is at blog.myAwesomeBlog.com, the secured url would be https://blog.myAwesomeBlog.com.

Now open your browser and type http://blog.myAwesomeBlog.com (yes, WITHOUT the ‘s’ in http). Not working uh?

No panic! Stop. Think. Make a thoughtful assumption. Ask yourself questions.

Does your website redirect to a secure protocol? Did you miss an option on heroku? How is this normally handled on other hosting services?

Bad news: you didn’t miss a configuration.

Middle-to-bad-news: You should handle it in your app.

Good news: I’ve got you covered.

A bit of context. Usually redirects are managed server-side, and usually hosting services offer this out-of-the-box from the load balancer/redirects configuration OR letting you write a custom .htaccess file than you can upload to the root of your project.

What’s an htaccess file? It’s a configuration file that apache servers can read to do handy things like redirects and routing (nginx has its own way of doing this through nginx_app.conf).

2019 Complete Guide To .HTACCESS - From The Basics To Advanced Learning Disclosure: Your support helps keep the site running! We earn a referral fee for some of the services we recommend.

How to redirect HTTP to HTTPS Using .htaccess Chrome and Firefox have started showing insecure warnings on sites without SSL certificates. Without SSL, your website…

How To Set Up A 301 Redirect In Htaccess A 301 redirect is a command for telling the search engines that a particular page has moved permanently and that you…

But, our fancy react/nextjs/whatever application uses node. Oouch, no straight way of doing this.

Rolling back to our thinking step, let’s investigate how do we handle this in express (the most used http server framework nowadays).

Express has the concept of middleware to extend functionalities of your server; by encapsulating logic in a middleware we can make the req flow down into a series of functions to ‘hook in’ and transform your response.

In Express a way to redirect to a secure protocol is to simply create a middleware to check for a property of the req object called req.secure (which is just an alias provided by express for req.protocol === https). If req.secure is true we do nothing, else we build a new url and redirect to it with a 301 status.

An example for this can be something like:

// Example middleware (not production-ready)
function requireHTTPS(req, res, next) {
  if (!req.secure) {
    return res.redirect('https://' + req.headers.host + req.url);
  }
  next();
}

Done, tested (or better the other way round in pure TDD’s way), shipped.

Hit the reload button once deployed and…

Example screenshot

Unhappily (and very strangely) this check will not work on Heroku and instead it will create an infinite redirect loop that will make your app unreachable.

So, in our never-ending search for the path of enlightenment we hit these pages:

Why am I getting a message 'Too Many Redirects'? - Heroku Help You have configured an SSL endpoint on your application and are redirecting requests to https however the browser…

Can Heroku force an application to use SSL/TLS? - Heroku Help You have configured an SSL endpoint and now you want your application to use https for all requests. Redirects need to…

Issue

You have configured an SSL endpoint and now you want your application to use https for all requests.

Resolution

Redirects need to be performed at the application level as the Heroku router does not provide this functionality. You should code the redirect logic into your application.

Under the hood, Heroku router overwrites X-Forwarded-Proto and X-Forwarded-Port request headers. The app must check X-Forwarded-Proto and respond with a redirect response when it is not https but http.

Which means, doing something like:

// Example Express middleware using X-Forwarded-Proto
function enforceSSL(req, res, next) {
  if (req.headers['x-forwarded-proto'] !== 'https') {
    return res.redirect('https://' + req.headers.host + req.url);
  }
  next();
}

Now, there is one more thing to consider before closing up. I also encountered a case where all of this was STILL giving me problems. The reason is the way Heroku manages end-to-end encryption and the Cloudflare plan that you’ve picked for your project.

If your plan is set to FULL you should be good to go, but if its on something like FLEXIBLE, then Heroku could try to fall to http protocol before redirecting and this can cause another loop. Make sure you read this before jumping from the window.

End-to-end HTTPS with Cloudflare - Part 3: SSL options The SSL section of the Cloudflare SSL/TLS app contains several options that determine whether Cloudflare securely…

Good, bad, ugly, but at the end of the day we’ve learned something new and made our tech lead happy. Isn’t that what we love doing?