Thursday, December 31, 2015

Elixir (Phoenix) App Custom Domain Redirect on Heroku Not Working Properly

TL;DR If your custom domain is [partly] working, but still redirects you to the herokuapp.com URL, you may need to remove force_ssl: [...] and change your scheme: "https" to "http" in your config/prod.exs. That said, if you're serving any sensitive data (i.e. user login, credit cards, etc.), DO NOT FOLLOW THIS :) Use SSL.

The other day I decided to make a personal site with a brief "Who am I" and resume.  Not that I'm looking for a job, but more so because I wanted something to do in Elixir and couldn't think of anything else that I could knock out in a couple hours.  I made the static site using using the Phoenix framework and pushed it to Heroku following Phoenix's awesome documentation.  Easy peasy!

The only old holdup I had was getting my custom domain to work properly.  I set up the CNAME and @ records as described in a well written StackOverflow post, albeit outdated, it did the trick for the most part.  Going to markevans.io redirected to my Heroku app as expected, but instead of the URL being markevans.io, it redirected to the herokuapp.com URL.  Ugh. I began to scour the internets and followed every post I could find about setting up DNS records on NameCheap and Heroku.  Spoiler alert, they all say pretty much the same thing and 99% of them are for Ruby/Rails apps.  The good thing is, as a Ruby developer, I can understand what's being done and how to translate it to my bare-bones Elixir/Phoenix app.

So what was the problem/solution?  The problem was SSL.  Phoenix's Heroku deployment documentation shows you how to deploy a secure app, which is great.  But my site isn't handling any sensitive data, there's no login, nothing to purchase... nada.  So really, I don't need SSL at this point and I don't want to spend any money on SSL certs (if your site handles *any* secure data, don't do what I did.  Set it up to work with SSL).

The solution, similar to a Rails app, is to not force SSL in your app.  As per the Phoenix-Heroku deployment documentation, your prod.exs should look like this:

config/prod.exs

config :myapp, Myapp.Endpoint,
  http: [port: {:system, "PORT"}],
  url: [scheme: "https", host: "bla-bla-bla.herokuapp.com", port: 443],
  force_ssl: [rewrite_on: [:x_forwarded_proto]],
  cache_static_manifest: "priv/static/manifest.json",
  secret_key_base: System.get_env("SECRET_KEY_BASE")


This setup works great if you're serving over SSL, but if you're not and don't plan to, it'll mess up your domain forwarding. Your custom domain will work, but you'll be redirected to the secure URL (Heroku's URL). To fix this, remove force_ssl: [rewrite_on: [:x_forwarded_proto]], and replace url: [scheme: "https",...] with url: [scheme: "http",...]. When you're done, your prod.exs should look like this:

config/prod.exs

config :myapp, Myapp.Endpoint,
  http: [port: {:system, "PORT"}],
  url: [scheme: "http", host: "bla-bla-bla.herokuapp.com", port: 443],
  cache_static_manifest: "priv/static/manifest.json",
  secret_key_base: System.get_env("SECRET_KEY_BASE")


Now git add . && git commit -m "removed force_ssl from production config", then deploy to Heroku. You should be good to go!