drawkcaB | Backward Compatible logo

rants and tips about software

Setting up real SSL with Node.js and Express

I got my single-domain certificate from Godaddy. Suddenly, I got myself with .key file, .csr file, and two .crt files. Most examples you can google on the Internet use self-signed certificates (which is basically useless for Internet use) and .pem files. Wft is .pem, you might ask?

After wasting hours trying to get this to work, I finally did. I hope more posts like mine get written and reach google index, so that people trying to set up production systems don't have to waste time. Here's how I did everything, step by step:

1. create your private key and certificate-request file. I used the command suggested by Godaddy as it requires 2048 bit key. Suppose your domain is domain.com:

openssl req -new -newkey rsa:2048 -nodes -keyout domain.key -out domain.csr

Most of the questions that follow are straightforward. Godaddy suggest you use domain.com for "Common name" field.

2. log into Godaddy, go to SSL menu and select Manage option. You actually buy a credit for SSL cert. so you need to "use" it, and then request a certificate. After using the credit and pressing "Launch" button I was welcomed with a screen saying zero (0) in all categories (certificates, requests, credits, etc.). This was rather confusing. Googling around, I found the solution: go to credits or certificates even though it says zero. After the page loads, an option appears to "update" the list. Click this and your credit shows up finally. Now, you can "request" the real certificate. Paste the content of domain.csr file you created in step 1. and wait for GD to create the cert.

3. after the cert is created, download it (there's a download option on the certificate screen). You'll get a .zip file containing two .crt files: domain.com.crt and gd_bundle.crt. First file is your SSL cert. The second file contains CA certs. of Godaddy that were used to digitally sign you cert. gd_bundle.crt might contain multiple certs. of which most browsers only need the first one, but it's better to install both. I've read some reports that some clients (ex. Android) require both to be installed properly.

4. Time to add all this to our Node.js/Express setup. It's a little bit different if you don't use Express (you need to call http.setSecure() with credentials):

var express = require('express');
var privateKey = fs.readFileSync('domain.key').toString();
var certificate = fs.readFileSync('domain.com.crt').toString();
var dad = fs.readFileSync('gd_bundle.crt').toString();
var app = express.createServer({key: privateKey, cert: certificate, ca: dad});
app.listen(443);
app.get('/', function(req, res){
    res.end('Hello SSL');
});

Supplying "ca" field to createServer is crucial, and missing from most examples on the net since they use self-signed certs.

Now, open http://domain.com and you should see the welcome message.

5. This works fine for my Firefox test. However, if you inspect the certs, you'll see that only one CA cert. is sent. To send both, we need to split gd_bundle.crt into two files and tell express to read both:

var dad1 = fs.readFileSync('gd_bundle.crt').toString();
var dad2 = fs.readFileSync('gd_bundle.crt').toString();
var app = express.createServer({key: privateKey, cert: certificate, ca: [dad1, dad2] });

That's all. I hope this saved you some time. In case it did, please follow me on twitter @mbabuskov, as I will post more Node.js stuff as I develop my applications.

Milan Babuškov, 2011-12-01
Copyright © Milan Babu┼íkov 2006-2014