SSL on wildcard domains on Heroku using GoDaddy

We have just finished setting up ssl on wildcard domains for a client. We have set this up on Heroku so that you have ssl on all top level subdomains.
For example:

*.myapp.com
demo.myapp.com
hello.myapp.com
secure.myapp.com

This is a fairly straightforward process, however there appears to be no good documentation online on how to do it for wildcard domains.

As much as I dislike GoDaddy with their automatic renewal on everything and massive upsell, they are the cheapest and easiest to get started with on an SSL wildcard package. Just make sure you don’t end up buying something irrelevant during the payment process!
I bought the “Standard (turbo) wildcard SSL 1 year” which costs around £124 excl VAT. I tried 123reg previously but it seems that 123reg certificates do not work completely cross browser.

So to get started lets generate a CSR. I am assuming Mac OSX for this, although this should also work on Linux, but probably not on Windoze.
Do the following:

mkdir sslcerts;
cd sslcerts;

Now generate a key. Choose a passphrase you will remember when it asks you for one

openssl genrsa -des3 -out mykey.key 2048;

And generate the CSR (using the passphrase you just entered). As you are doing a wildcard domain make sure the organisational unit name and the common name are the same and are pre-pended with a * (see below for example).

openssl req -new -key mykey.key -out mycsr.csr;

Country Name (2 letter code) [AU]:GB
State or Province Name (full name) [Some-State]:London
Locality Name (eg, city) []:Croydon
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Ltd
Organizational Unit Name (eg, section) []:*.exampleapp.com
Common Name (eg, YOUR name) []:*.exampleapp.com
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Leave the challenge and company name blank.

Double check you got this all correct as when you paste your CSR in, if you get the domain wrong you will have to request a refund and then reapply, not the quickest of processes! If you do this wrong, the best way to get a refund on it is to call them up.
You now paste your CSR up to the GoDaddy panel and then go through a series of confirmations on your domain. When you have finished these, the certificate will be issued.

Download your certificate and intermediate key (they come in a bundled dir). When you download choose “Other” as the format. You need to combine the two certificates so first move the two to your directory and then combine them:

cat myapp.com.crt gd_bundle.crt > myapp_bundle.crt;

Also bundle your cert and key together:

cat myapp_bundle.crt mykey.key > mypem.pem;

Finally we now need to remove the passphrase from the certificates:

openssl rsa -in mypem.pem -out final.pem;
openssl x509 -in mypem.pem >>final.pem;
openssl rsa -in mykey.key -out final.key;

And that is your certificates done and ready to upload to heroku.
Now on heroku log in and check that you have the Custom Domains and Custom Domains and wildcards add-ons and that your domain names are set correctly (ie that you have *.myapp.com and myapp.com set as domain names).

Now upload your ssl certs to heroku:

heroku ssl:add final.pem final.key

From you heroku control panel add Hostname SSL. Heroku will then send you an email with a DNS address for your app such as:

appid42352herokucom-324234.us-east-1.elb.amazonaws.com

Make sure you domain is pointing to this, so remove the existing CNAME record you have for your wildcard subdomains:

*.myapp.com.  -> proxy.heroku.com.

And create a CNAME record to make it point to the new amazon appid:

*.myapp.com. -> appid419658herokucom-96892355.us-east-1.elb.amazonaws.com.

Now this should all be working and after waiting for your CNAME to propagate, you should now be able to visit mysubdomain.myapp.com using ssl (https) and it should be valid and secure :-)

As a final quick hint, if you want to make sure that http requests get redirected to https automatically put the following in “lib/middleware/force_ssl.rb”:

class ForceSSL
  def initialize(app)
    @app = app
  end

  def call(env)
    req = Rack::Request.new(env)
    if env['HTTPS'] == 'on' || env['HTTP_X_FORWARDED_PROTO'] == 'https'
      @app.call(env)
    else
      [301, { "Location" => req.url.gsub(/^http:/, "https:") }, []]
    end
  end
end

The following into “config/application.rb”:

config.autoload_paths += %W( #{ config.root }/lib/middleware )

And the following into “config/environments/production.rb”:

config.middleware.use "ForceSSL"

Now your app will automatically route any http request to https, meaning ssl the whole time :-)
I grabbed this little bit of code for the SSL from somewhere but can’t remember where so please comment if you are the poster and I will credit you, thanks!

edit the ssl was taken from: Simone Carletti @ stackoverflow: http://stackoverflow.com/questions/3861772/force-ssl-using-ssl-requirement-in-rails-app

19 Comments

RSS feed for comments on this post. TrackBack URL

  1. admin — February 15, 2011

    This will work cross browser. If it is not working for IE and you are getting a certificate warning, please check that your date is set correctly for your computer.

  2. Sean — February 17, 2011

    Thanks for the write-up! Strangely just two days before I’m doing this for my site!

    Ran into a snafoo though. Upon pasting my CSR into Godaddy’s field, I’m getting the following error:

    “The name entered in the CN field of the CSR MUST be the fully-qualified domain name for the Web site you will be using the certificate for (e.g., \”www.domainnamegoeshere.com\”), or a valid Intranet domain name. Do not include the \”http://\” or \”https://\” prefixes in your common name. The common name cannot include spaces. Do NOT enter your personal name in this field.”

    This is after triple checking that the Common Name I entered was: *..com

    Any clues? Thanks :)

  3. Jason Green — February 17, 2011

    Are you deffo purchasing the correct SSL certificate? I would say that would suggest that you did not get a wildcard ssl?

  4. wildcard ssl certificate — February 17, 2011

    Thanks for writing up this post, I’ve been having a lot of trouble with Heroku that I just couldn’t get my head around. Then I stumbled across this post and it solved the problems I was having. Thanks again, James.

  5. Jason Green — February 17, 2011

    thanks!

  6. Brendan Kemp — February 18, 2011

    Nice writeup, thanks!

    From my quick google, it looks like Simone Carletti at stackoverflow was the first to post this technique: http://stackoverflow.com/questions/3861772/force-ssl-using-ssl-requirement-in-rails-app

    This blog post also references Simone’s answer: http://clearcove.ca/blog/2010/11/how-to-secure-a-rails-app-on-heroku-with-ssl-firesheep/

  7. Jason Green — February 18, 2011

    Thanks will add the reference to the post.
    Can’t say I have seen the other post before but that is a good writeup too!

  8. Simone Carletti — February 19, 2011

    > I grabbed this little bit of code for the SSL from somewhere but can’t remember where so please comment if you are the poster and I will credit you, thanks!

    Here I am! :D
    Thanks for featuring my code.

  9. Jason Green — February 19, 2011

    Thanks Simone :) Great bit of code

  10. Bikash Basukala — April 28, 2011

    I hope community can help our problem !

    We have an app recently deployed to Heroku. I think we have hit the wall in terms of our requirements (please make my conclusion wrong ) .

    It’s a project management app. Management has decided to go for all SSL solution hence we got ourselves wildcard certificate ( *.ourapp.net) from GoDaddy which we added successfully to Heroku under Hostname based SSL. Hostname based SSL requires putting particular CNAME pointed to AmazonAWS url which is given by Heroku. For example , if we wanted to secure var.ourapp.net we will have to point CNAME var.outapp.net —-> appid42352herokucom-324234.us-east-1.elb.amazonaws.com [this is example URL)

    Since we wanted every first-level subdomain to be secure, we had to put *.myapp.net CNAME pointed to AmazonURL.

    But this interferes with our application design where every wildcard subdomain needs to be processed such that each customer could get branded URL like myname.outapp.net

    can you suggest anything please ?

    thanks in advance

  11. Prathan Thananart — July 25, 2011

    Maybe Heroku have updated their system, but I’ve found that you don’t need to ssl:add the pem file, just the crt will do. In fact trying to upload the pem file resulted in an “unable to allocate SSL endpoint” error for me.

    Another thing worth noting is to my knowledge GoDaddy doesn’t let you use a wildcard in a CNAME entry. My team got around this by putting an A record instead and praying Heroku doesn’t move its IPs around. This feels awfully brittle; please suggest if anyone’s got a better idea.

  12. Ben — August 15, 2011

    Hey,

    I tried following a combination of your tutorial and the one that is on Heroku since I don’t have a certificate from godaddy but from dnsimple.

    My problem is, that I have the pem and key file. When I trie to generate the passphrase less pem version I am getting an unable to load private key.

    Do I need to add the key file at the top of the pem file or at the bottom of it?

    Thanks

  13. Kai Middleton — August 26, 2011

    Some of the command line examples you give don’t render properly. They render as gt and lt entities instead of the greater-than or less-than symbols. It makes for extra work to copy them into a terminal.

  14. Kai Middleton — August 26, 2011

    Another small question: you wrote: “You now paste your CSR up to the GoDaddy panel ” Does that mean that this command:

    openssl req -new -key mykey.key -out mycsr.csr;

    generates some output to the terminal that I cut and paste into the GoDaddy panel?

  15. Jason Green — September 1, 2011

    Yeah I think that is probably due to a recent upgrade on the blog and is something I will look at. Thanks for letting me know!

  16. Kai Middleton — September 19, 2011

    The above steps didn’t work with Android. “Cannot Verify Server Identity”, even though on a laptop it worked fine. Reading the heroku doc, http://devcenter.heroku.com/articles/ssl , I found the following: “You must remove the passphrase from your certificate so Heroku can automatically start the server (Do this before adding your chain or intermediate certificate)”. Therefore, I changed the steps to be as follows (many of the steps I give are the same, I give those for context):

    openssl genrsa -des3 -out mykey.key 2048
    openssl req -new -key mykey.key -out mycsr.csr
    # download the zip file from GoDaddy; it yields myapp.com.crt and mykey.key
    cat myapp.com.crt mykey.key > mypem.pem
    openssl rsa -in mypem.pem -out final.pem
    openssl x509 -in mypem.pem >> final.pem
    openssl rsa -in mykey.key -out final.key
    cat gd_bundle.crt >> final.pem
    heroku ssl:add final.pem final.key
    # etc…

    Now it works in Android too.

  17. Jason Green — September 20, 2011

    thanks kai :-)

  18. Jonathan Dance — November 11, 2011

    Hello,

    Your steps for combining / preparing your certificates for Heroku are incorrect. The steps should be as follows:

    1. Combine your certificate with the GoDaddy bundle (gd_bundle.crt) which you can here: https://certs.godaddy.com/anonymous/repository.seam) to create your complete certificate:

    cat yourdomain.com.crt gd_bundle.crt > final.crt

    2. Create a passphrase-free private key:

    openssl rsa -in mykey.key -out final.key

    3. You can now add your finished certificates to Heroku:

    heroku ssl:add final.crt final.key

    4. Then add your desired SSL addon:

    heroku addons:add ssl:hostname

    Thanks!
    Heroku Support

  19. Frank — January 28, 2012

    So i guess the question i have is:

    can i secure my domain “www.domain.com” so that it looks like “https://www.domain.com” on heroku with this wildcard SSl or is that impossible?

Leave a comment

Preview: