I’ve had a few requests to go over setting up a Wildcard SSL cert, especially as it relates to things like CDN’s, subdomains, etc. So I wanted to put a guide out there so people can get help for an issue that is surprisingly frustrating to find information about.
If you’ve read my other guide to setting up SSL, you’ll have a good basis for what we are about to do, and many steps I mention below will be the same. But I’ll go through the whole process anyway, so you won’t have to do the math as to where to stop, change things, and start again on.
Basic Steps:
- Install openssl if you haven’t already (via homebrew, from source, etc.).
- Generate keys using openssl
- Purchase and Activate Wildcard SSL certificate from Namecheap
- Create server.crt from certificates emailed to you
- Provision Heroku SSL endpoint
- Update your DNS settings on Namecheap
- Force SSL on Production
- Check to make sure SSL is working properly for the root domain
Advanced Steps:
- Set up your wildcard certificate with Amazon Cloudfront as a CDN subdomain (https://cdn.example.com)
- Set up your wildcard certificate with Ghost JS Blogging as a blog subdomain (https://blog.example.com)
Just the code:
BASIC STEPS
Install Open SSL: (almost all of this will be done from the command line)
Is OpenSSL already installed? openssl version
If already installed, it should return: OpenSSL X.X.Xx D MON YEAR
Where X.X.Xx is the version number (1.0.1a for example) and D MON YEAR is the day month and year – eg something like 31 Mar 2014 If it’s not installed, it will say something like -bash: openssl: command not found
In which case you need to install it.
- On Ubuntu:
sudo apt-get install openssl
- On Mac:
brew install openssl
(this assumes you have Homebrew installed)
Generate Keys Using OpenSSL
Run the command from a folder or location you’ll remember it: openssl genrsa -des3 -out server.pass.key 2048
This should lead to the output:
Generating RSA private key, 2048 bit long modulus ......+++............................................................................................................+++ e is 65537 (0x10001) Enter pass phrase for server.pass.key:
Go ahead and enter a passphrase here if you want. I generated a random one with > 14 random digits/numbers/symbols. Be sure to remember this code as you might need it later. Now run:
openssl rsa -in server.pass.key -out server.key
This should lead to the output:
Enter pass phrase for server.pass.key:
Enter the passphrase we entered earlier. Now it should say:
writing RSA key
Once that is complete (instantaneous), run the next command:
openssl req -nodes -new -key server.key -out server.csr
You’ll now be prompted with the following fields:
-
Country Name (2 letter code) [AU]:
See: http://www.ssl.com/csrs/country_codes. For those living in the United States, it’s `US` (without the quotes) State or Province Name (full name) [Some-State]:
Full name of the state, eg `California`-
Locality Name (eg, city) []:
For us living in the US, most likely a city. So something like `San Francisco` -
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Name of your company: eg ExampleCo, Google, etc. -
Organizational Unit Name (eg, section) []:
I just used “Web Security” for mine. They are looking for a department (Marketing, etc). -
Common Name (e.g. server FQDN or YOUR name) []:
BE CAREFUL WITH THIS ONE! For those keeping score from my other article, this is where I start to differ. What we put here is the wildcard URL, eg *.example.com. -
Email Address []:
Put a good email contact here, something like [email protected] -
Please enter the following 'extra' attributes
Feel free to skip past any last “extra” attribute things, they shouldn’t affect anything.
Purchase and Activate Wildcard SSL certificate from Namecheap
Since we want to have an SSL certificate that works not only on our base domain (eg, example.com and www.example.com) but also our subdomains (blog.example.com, cdn.example.com, etc), we’ll need a wildcard certificate. On Namecheap, the wildcard certificates should be listed here:
https://www.namecheap.com/security/ssl-certificates/wildcard.aspx
They’ll run you anywhere from $94/year – $389/year (current prices: March 2015). If you are wondering what the more expensive wildcard certificates get you, some will give you more robust warranties (the biggest warranty being $1.2 million vs at the low end $5,000), while others will give you a green bar when you go to the website (see: https://globalsign.tbs-certificates.co.uk/images/ev2.jpg), higher levels of encryption, site seals, etc.
Since this guide is about PositiveSSL, let’s go ahead and buy the PositiveSSL Wildcard certificate, which costs $94/year.Once you have purchased some SSL certs, they should appear in your account here:
https://manage.www.namecheap.com/myaccount/ssl-list.asp
Click “Activate Now” next to the wildcard SSL certificate you have not yet initiated (the top one in the image, called POSITIVESSL WILDCARD). You will be taken to a new page that asks you to verify some details. First, go back to where you generated the server.csr, server.key, and server.pass.key files. Open up server.csr, and copy everything between the BEGINNING and END blocks. It should look something like:
xxxxxxxxxxxxxxxxxxxxxxxxxxxx9xxxxxxxxx9xxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxx9xxx9xxxxxxxxxx9xxxx9xxxxxxxxxxxxxx99xxxxxxxxxxxxx
xxxxxx9x9xx9xxxxxxxxxxxxxxxxxxx9xxxxxxxxxxxxxx9xxxxxxxxxxxxxxxxx
xxx9xxxxxxxxxxxxxx9xxxxxxxxxxx9xx99xxxxxxx9xxxxxxxx9xxxxxxxxx9xx
xxxxxxxxxxxxxxx9xx9xxxxx9xxxxxxxxxx/x9xxxxx9xxxxxxxxxxxxxxxxxxxx
xxxxxx99xxxxxxx9xxx9x99xxxxxxxx9xxxxxxxxxx9x9xx9xxxx99xxx+9xxxxx
xxx9x/xxxxxxxx9xxxxxxxxxx/xxx9xxxxxxxx9xxxxxxx9xxxx9xxxx9x9x9xxx
xxxxxxxxxxxxxxxxxxx++9xxxxxxxx99x9xx/xxxxxxxxxx9x+xxxx9xxxxx9xxx
xxx9xxxxxx9xxxxxxxxxxxxxxxxxxxxxxxx9x/x/xxxxx9xxxxxxxx9xxx99xxxx
9x99xxxxxxxxxx+xx9+/9xxxxxxxxxxxxxxxxxxxxx9x9xxxxxxx9xxxxxxxx9xx
xxxxxxxxxxxxxxxx9xxxxxxxxxxxxxxxx9xxx9xxxxx9xxxxxxxxxxxxx9xx9xx9
xxxxx/xxxx9xxxxxxxxxxxxxxxxxxxxx9xxx9xxxxx99xxxxxxxxxxxxxxxxxxx9
xxxx9xxx/xx9x9xxxx+xx+xxxxxxx/xxxx9xxxx9xxxx99xxxxxxxxxxxxxxxxxx
9xx9xxxxxxxxxxxxxxxx99xxxxxxxxxxxxx/9xxx9xx+99xxxx99xxxxx9xxxxxx
xxx9xx9xxxxxx9xx9x9xx+xxxxxxxxxx9xxxxxxxx+9xxx9x9xxx99xxxxxxxxxx
xxxxxxxx+x/x9x9xxxxx9xxx99xx9xxx==
For “Select web server”, choose “Apache 2”. Your page should now look like:
I’ve obviously put a non working key here, you’ll have to use your own 😉 It might ask for an admin email to send to. While you could setup your own email server, email forwarding will work as well. Go to the list of all your domains, click on your domain, and select “Email Forwarding Setup” from the left hand side. Then create a forwarding email like [email protected] that forwards to [email protected]. After a few minutes, you should get an email that asks you to confirm that you asked to issue a SSL certificate. Click the link provided and enter in the verification code they provided for you.
Create server.crt from certificates emailed to you
We’re almost there! After confirming our SSL certificates, you will get emailed a zip file with the following four files:
- Root CA Certificate – AddTrustExternalCARoot.crt
- Intermediate CA Certificate – COMODORSAAddTrustCA.crt
- Intermediate CA Certificate – COMODORSADomainValidationSecureServerCA.crt
- Your PositiveSSL Certificate – STAR_example_com.crt
It’s now as simple as running the following command from the terminal:
cat STAR_example_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > server.crt
No need to worry about forgetting to copy certain pieces, or forgetting line breaks, or any of that! Boom! File!
Provision Heroku SSL endpoint
In your rails app folder that you want to add SSL to, run:
heroku addons:add ssl:endpoint
Now gather your server.crt file that you created just a second ago, and find your server.key that you generated from one of the first beginning steps. Once they are all in the same location, run:
heroku certs:add server.crt server.key
You should now see your console say something like:
Adding SSL Endpoint to example... done example now served by xxxx-9999.herokussl.com.
Where XXXX is a fancy name (rosebud), and 9999 is a number (very similar to generating an app on heroku without naming it)
Update your DNS settings on Namecheap
Now either update or create your DNS records on NameCheap to point to the new domains. Go back to all your domains (https://manage.www.namecheap.com/myaccount/domain-list.asp), click on your domain, then click on “All Host records” once that page loads (on the left side list). Your records should look something like: HOST NAME IP ADDRESS/URL RECORD TYPE @ https://www.example.com URL REDIRECT www xxxx-9999.herokussl.com CNAME(ALIAS)
Force SSL on Production
Go to config/environments/production.rb and there should be a commented out line that says: config.force_ssl = true
Go ahead and uncomment that line out and push up to Heroku.
Check to make sure SSL is working properly
Did it work? Are we done? Only one way to check. Wait about 10 minutes (usually sooner, mine worked about 2-3 minutes after), and then visit your https website — it should work! Problems? Try using https://www.digicert.com/help/ to check to see what problems it can find with your SSL certificate.
ADVANCED STEPS
Set up your wildcard certificate with Amazon Cloudfront as a CDN subdomain (https://cdn.example.com)
For this step, we will need to have the aws-cli installed (download it here, along with setup instructions for Linux/Mac available on this page). For Mac / OSX, if you have brew installed, it’s as easy as:
brew install awscli
Once installed, it needs to be configured properly. run:
aws configure
And be ready to provide it with an access key id and secret access key. If you don’t have one, create one through the IAM Management console on Amazon, by creating a new user with name something like “example.com-cloudfront-access”, and giving it a policy for CloudFront access.
Once your aws-cli tool is configured properly, we can push up our wildcard certificate to CloudFront. First CD from the terminal into the directory where your server certificate information was (STAR_example_com folder). Before we run the command to upload the SSL certificate, we need to include all intermediary certificates together (COMODORSADomainValidationSecureServerCA.crt, COMODORSAAddTrustCA.crt, and AddTrustExternalCARoot.crt) into a single crt file. This is a huge thing that people miss, and it can cause a bunch of errors / failures when a site does not show up as trusted because an intermediary certificate wasn’t included. So if from ruby, you get some error that looks like:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
You might very well check the URL you are looking up to make sure it’s SSL certificate is properly installed (again, I recommend using https://www.digicert.com/help/ to help diagnose any issues).
To cat the intermediary certificates together, run:
cat COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > certificate-chain.crt
Now we can upload everything to Cloudfront. Run the following command (I’ll explain the variables after the code):
aws iam upload-server-certificate --server-certificate-name DEMO_DEMO_DEMO --certificate-body file://STAR_example_com.crt --private-key file://server.key --certificate-chain file://certificate-chain.crt --path /cloudfront/
Where DEMO_DEMO_DEMO is a name you’ll recognize once it’s up on Cloudfront, STAR_example_com.crt is a file in the STAR_example_com directory, server.key is the key we generated near the beginning of this guide, certificate-chain.crt is the concatenated intermediary certs that help establish “Trust”, and cloudfront is the path we are uploading to.
If everything went well, you should get a message back from heroku:
{
"ServerCertificateMetadata": {
"ServerCertificateId": "AAAABBBBCCCCDDDDEEEE",
"ServerCertificateName": "DEMO_DEMO_DEMO",
"Expiration": "2016-01-06T23:59:59Z",
"Path": "/cloudfront/",
"Arn": "arn:aws:iam::9999999999:server-certificate/cloudfront/DEMO_DEMO_DEMO",
"UploadDate": "2015-02-21T10:23:57.185Z"
}
}
Now, login to the Amazon AWS console and go to Cloudfront, clicking on the Cloudfront domain you want to associate with your website. Click the general tab (if you aren’t there already), and then click edit. Then choose the following options:
For “Alternate Domain Names (CNAMEs)”, put down the subdomain you want to use for your CDN (in this example, cdn.example.com). Then select the “Custom SSL Certificate (stored in AWS IAM)” option, and choose the certificate from the dropdown that you uploaded (in this example, DEMO_DEMO_DEMO). For “Custom SSL Client Support”, choose “Only Clients that Support Server Name Indication (SNI)”. While it might be tempting to choose the All Clients option here, if you click through to pricing you get a sticker shock — selecting this option will set you back $600/month. Not for me! Go ahead and click save now that everything is chosen.
Now head back over to Namecheap to complete the subdomain setup. Click on your domain, and go to the host records for your domain (All Host Records from the left sidebar), and setup your CDN subdomain as follows:
Set a new host record with “cdn” as the HOSTNAME, your Cloudfront url (a1b2c3d4e5.cloudfront.net for example) as the IP ADDRESS/ URL, and CNAME as the ALIAS/RECORD TYPE.
20 minutes from now, if everything was configured correctly, https://cdn.example.com should work (but make sure and go and check for errors through https://www.digicert.com/help/ anyways)! Now all that’s left to do is update your heroku config with the right settings. If you originally setup Cloudfront using Heroku’s guide, you’ll have a line in your config/production.rb file that looks like:
config.action_controller.asset_host = ENV["CDN_HOST"]
To set or reset the variable on heroku, simply run from the terminal:
heroku config:set CDN_HOST=cdn.example.com