Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Heroku SSL on root domain

I am trying to setup SSL for my heroku app. I am using the hostname based SSL add-on. The heroku documentation states the following:

Hostname based SSL will not work with root domains as it relies on CNAME 
aliasing of your custom domain names. CNAME aliasing of root domains is 
an RFC violation. 

As expected everything works well when I access the site using the www subdomain, i.e. https://www.foo.com. The browser complains when I access https://foo.com as the certificate presented is for heroku.com.

I concluded that I have to redirect the traffic for foo.com to www.foo.com to address this issue. I am considering following approaches:

1) DNS based redirection

The DNS provider Zerigo supports the redirect records. I came across a question on a similar subject on SO. I tried the solution, it works ONLY for HTTP redirection(Zerigo documentation confirms this).

My Zerigo configuration:

foo.com      A             x.x.x.x
foo.com      redirect      http://www.foo.com
www.foo.com  CNAME         zzz.amazonaws.com

2) Rack based redirection

Add a rack based middle-ware to perform the redirection. The canonical-host gem provides such support.

use CanonicalHost do
  case Rails.env.to_sym
    when :staging     then 'staging.foo.com'
    when :production  then 'www.foo.com'
  end
end

I am wondering if there is a better solution for this(barring switching to $100 per month IP based SSL)

like image 555
Harish Shetty Avatar asked Jul 15 '11 00:07

Harish Shetty


People also ask

How do I enable SSL on Heroku?

Configuring SSL In Heroku, go back to the Settings tab of your application and scroll down to Domain and certificates. You should now see a white button Configure SSL. Click on it. Leave the Automatically option ticked and click on Continue.

Does Heroku provide SSL?

Heroku SSL is a combination of features that enables SSL for all Heroku apps. Heroku SSL uses Server Name Indication (SNI), an extension of the widely supported TLS protocol.

Does Heroku have SSL for free?

Heroku SSL is free for custom domains on Hobby dynos and above and relies on the SNI (“Server Name Indication”) extension which is now supported by the vast majority of browsers and client libraries.


4 Answers

Wow...this took me forever, and a bunch of info on the web was wrong. Even Heroku's docs didn't seem to indicate this was possible.

But Jesper J's answer provides a hint in the right direction: it works with DNSimple's ALIAS record which I guess is some new sort of DNS record they created. I had to switch my DNS service over to them just to get this record type (was previously with EasyDNS).

To clarify when I say "works" I mean:

  • entire site on SSL using your root domain
  • no browser warnings
  • using Heroku's Endpoint SSL offering ($20/month)

It works for all of the following urls (redirects them to https://foo.com with no warnings)

  • http://foo.com
  • http://www.foo.com
  • https://www.foo.com
  • https://foo.com

To summarize the important bits.

  1. move your DNS over to DNSimple (if anyone knows other providers offering an ALIAS record please post them in the comments, they were the only one I could find)
  2. setup Heroku endpoint ssl as normal https://devcenter.heroku.com/articles/ssl-endpoint
  3. Back in DNSimple add an ALIAS record pointing foo.com to your heroku ssl endpoint, something like waterfall-9359.herokussl.com
  4. Also add a CNAME record pointing www.foo.com to your heroku ssl endpoint, waterfall-9359.herokussl.com
  5. finally in your rails (or whatever) app make the following settings:

in production.rb set

config.force_ssl = true 

in application_controller.rb add

before_filter :check_domain  def check_domain   if Rails.env.production? and request.host.downcase != 'foo.com'     redirect_to request.protocol + 'foo.com' + request.fullpath, :status => 301   end end 

This finally seems to work! The key piece seems to be the ALIAS dns record. I'd be curious to learn more about how it works if anyone knows, and how reliable/mature it is. Seems to do the trick though.

like image 114
Brian Armstrong Avatar answered Oct 06 '22 00:10

Brian Armstrong


DNSimple offers an ALIAS record type to address this need. You can create an alias from your root domain (a.k.a zone apex) pointing to a CNAME. Read more about it here:

http://blog.dnsimple.com/introducing-the-alias-record/

like image 27
Jesper J. Avatar answered Oct 05 '22 23:10

Jesper J.


DNS redirects wouldn't care whether the inbound request is http or https so would maintain the original protocol - so would redirect http://foo.com to http://www.foo.com and the same for https.

You'll need to do it within the application via the gem you found or some other rack redirect gem or if www. is a problem use the IP based SSL addon.

like image 34
John Beynon Avatar answered Oct 06 '22 01:10

John Beynon


One thing you will like to keep in mind is that google might index both versions of your site if both versions are accessible (Root vs WWW). You would need to setup conicals to handle that which might be a pain to upkeep.

In my DNS settings I set up a URL / Forward record (DNS Simple)

URL foo.com     3600        http://www.foo.com

The CNAME setup only needs to be setup for WWW

CNAME   www.foo.com 3600        providedsslendpoint.herokussl.com

I also had to setup and Alias for my root

ALIAS   foo.com 3600        providedsslendpoint.herokussl.com

Then I decided to simply replace foo.com with an env variable ENV['SITE_HOST'] (Where SITE_HOST= www.foo.com or whatever I might define). I can control this via my heroku configuration or my .env file (See https://github.com/bkeepers/dotenv). That way, I can control what happens in different environments.

For example, my test app uses test.foo.com as the url it also has its own SSL endpoint so that works fine for me. This also scales to create staging or qa specific environments as well.

  before_filter :check_domain

  def check_domain
    if Rails.env.production? || Rails.env.testing? and request.host.downcase != ENV['SITE_HOST']
      redirect_to request.protocol + ENV['SITE_HOST'] + request.fullpath, :status => 301
    end
  end

From now on, end users will always access www with forced SSL. Old links will suffer a small hang but nothing noticeable.

like image 42
Rodrigo Garcia Najera Avatar answered Oct 06 '22 01:10

Rodrigo Garcia Najera