How to add SSL to your Heroku custom domain with SSLMate

All sites hosted on Heroku that use the default herokuapp.com domain name are available via HTTPS at no additional cost. However, to use SSL with a custom domain name, you have to buy and install your own SSL certificate. In the past, this used to be a complicated and time-consuming process, but today, with companies like SSLMate, it only takes a few minutes.

At the time of writing, the two easiest ways to configure SSL for a custom domain on Heroku are via SSLMate, and the ExpeditedSSL Heroku add-on. I personally chose SSLMate because it is significantly cheaper, while being very easy to use.

Whether you choose SSLMate or ExpeditedSSL, you will also have to buy Heroku's SSL add-on, which costs $20/month. So, for a single-subdomain certificate, the total yearly cost with SSLMate is $256 ($240 Heroku costs + $16 SSLMate certificate), versus $420 with ExpeditedSSL ($240 Heroku costs + $180 ExpeditedSSL certificate). For wildcard certificates, the savings are even greater with SSLMate: $390 vs $1188.

Before you can use SSLMate, you'll need a few prerequisites: a free SSLMate account, Homebrew (on OS X), the Heroku toolbelt, and an email address at your domain with any of the following prefixes: admin@, webmaster@, administrator@, hostmaster@, postmaster@. The process for setting up this email address will depend on where your domain is managed. I use Hover, so I bought a forward-only email, then visited the Manage Your Email page, and created a webmaster@ address for the domain name I wanted to use on Heroku, and set it to forward to one of my existing email addresses (not related to my domain).

Once the prerequisites are in place, you can install SSLMate. On OS X, it's as easy as any other Homebrew installation:

$ brew update && brew install sslmate

For other operating systems, visit the SSLMate installation page.

To avoid having to type your SSLMate username and password over and over, you can choose to allow SSLMate to remember your credentials with this command:

$ sslmate link

Next, create a directory for keeping your certificate files, and cd into it. I used a top-level generic directory for keeping all certificates, then domain-specific subfolders. For example:

$ mkdir ~/ssl-certs/admin.example.org
$ mkdir ~/ssl-certs/wildcard.example.org
$ cd ~/ssl-certs/wildcard.example.org

Whether you buy a single-subdomain certificate or a wildcard certificate will depend on how many subdomains you plan on pointing to the same Heroku app. You can only upload one certificate per Heroku app, so if your app requires more than one subdomain, you'll have to buy a wildcard certificate.

To buy a wildcard certificate, run this command, making sure to replace example.org with your own domain name, and making sure to keep the quotes:

$ sslmate buy '*.example.org'

Follow the on-screen instructions, and after you select your email address, you should receive an email from either Comodo or GeoTrust (the two providers SSLMate currently works with). I received mine from Comodo, and the verification consisted of clicking the verification link in the email, then entering the code from the email into the Comodo website. Once my purchase was verified, SSLMate started automatically downloading the certificate files to my computer.

Next, you'll need to upload all four certificate files to your Heroku app. First, make sure your Heroku toolbelt is up to date:

$ heroku update

Next, purchase the Heroku SSL endpoint for your app, making sure to replace your-heroku-app with your actual Heroku app name:

$ heroku addons:add ssl:endpoint -a your-heroku-app

Finally, upload the files to your app by copying and pasting each one after heroku certs:add:

$ ls # to see the files in your certs directory
$ heroku certs:add *.example.org.chain.crt *.example.org.chained.crt *.example.org.crt *.example.org.key -a your-heroku-app

The output of the above command should include your new Heroku SSL endpoint. Copy it as you'll need it in the next step. It should be something like example-2121.herokussl.com.

If you haven't already done so, add the subdomains you plan on using to your Heroku app:

$ heroku domains:add www.example.com -a your-heroku-app
$ heroku domains:add admin.example.com -a your-heroku-app

If you only have one Heroku app for your domain name, and you plan on using multiple subdomains, you can add a wildcard domain:

$ heroku domains:add *.example.com

Next, go to your domain management website (such as Hover), and edit the CNAME for your subdomain to point to your Heroku SSL endpoint. If you're only using one Heroku app for this particular domain, you can use a wildcard (*) for the CNAME. Otherwise, you'll have to add a CNAME for each subdomain and point it to the app's Heroku SSL endpoint.

CNAME changes can take a while to propagate, so if your website traffic comes from all over the world, you might want to wait a day or two before automatically redirecting all HTTP traffic to HTTPS. I came across a few sites that claim to check propagation for you, such as whatsmydns.net, but I found that even though they said the site was fully propagated, browsers still warned that the certificate could not be trusted. If anything, I would at least wait until you can access your HTTPS site on a variety of browsers.

Once browsers recognize the certificate, the next step is to test your site over HTTPS and make sure you don't see any errors in the browser's developer console. A common error is that external sites, such as those where your fonts might be hosted, are being called via HTTP instead of HTTPS.

Once you're confident your site is working over HTTPS, you can force all traffic to your site to use SSL. That means if someone visits http://www.example.com, they will automatically be redirected to https://www.example.com. In a Rails app, it's as easy as enabling the following setting in your config/environments/production.rb file:

config.force_ssl = true

One final note I'll make is that visiting your naked domain name over HTTPS (such as https://example.com, without the www.) won't work unless your domain management tool supports CNAME functionality at the apex. Hover doesn't currently support this, but they are working on it.

More resources

For more details about why it's a good idea to use HTTPS, and how to configure it for Nginx and other hosts, check out Eric Mill's article, Switch to HTTPS Now, For Free.