In my guide on setting up Nginx I included tweaks for caching SSL sessions and limiting the ciphers that are accepted, but I didn’t cover how I actually store and manage SSL certificates or go into how you create the pem
files that Nginx uses.
By convention, I create a new directory to house all SSL certificates: /etc/nginx/ssl
. I ramp down the permissions on it so that only root can access it, as Nginx starts off as root before spawning its individual worker processes:
sudo mkdir /etc/nginx/ssl sudo chown -R root:root /etc/nginx/ssl sudo chmod -R 600 /etc/nginx/ssl
Generating Your SSL Key and CSR
Ready to get a new SSL certificate? You’ll need to generate a private key and a CSR.
The Private Key
There are various recommendations on the length of keys you should use. In general I would never use a 1024 bit key anymore. With 2048 you should be good right now, but I’ve never found any practical reason not to go big… All my private keys are 4096 bits in length.
Note that some certificate authorities’ generation tools won’t support anything bigger than 4096, so don’t lose your head just yet.
So move into your new Nginx SSL directory and get started by generating your key: sudo openssl genrsa -out domain.com.key 4096
You should see your box churn for a while, and then you have a shiny new RSA private key named domain.com.key
.
The Certificate Signing Request
The next step is to create the signing request for your new certificate. This is what your certificate authority will parse to get the information they need to include on the certificate.
Different CAs use different pieces from this request. Some will only use it to get the private key they need to generate the certificate for, others will use all the organization information from it.
You have to tell OpenSSL which key to use in generating the CSR (the one you just created), and then answer a bunch of questions. Remember that the domain name you’re generating it for goes in the “Common Name” value.
If you’re generating a certificate for a root domain (ie: example.com, not mail.example.com, etc.) don’t include the “www” subdomain. Most CAs will automatically add the www subdomain as an alternate name to the certificate for a root domain, but won’t necessarily realize that a request for www.example.com should be changed to example.com and have www.example.com added… This is especially important if you’re adopting no-www.
sudo openssl req -new -key domain.com.key -out domain.com.csr
After answering all the questions, domain.com.csr
is the file you need to upload to your CA when prompted.
The Final Step: Your Certificate Chain
After your CA has generated your certificate you should end up with a new crt
file. For your own sanity down the line, make sure it’s named in the same pattern we’ve used for the other files: domain.com.crt
and upload it to your server and move it to your Nginx SSL directory.
Intermediate Certificate Authorities
Now for a little background on why we have to go through this hassle.
Every operating system (the one on your computer, the one on your server, the one on your phone) has a list of trusted “root” Certificate Authorities1. These are the big players that have spent a ton of money on supposedly securing their infrastructure (though it seems every week one of them has screwed up or been compromised lately): AOL Time Warner, Comodo, Equifax, Verisign, the US DoD…
In the old days you’d have to have gone to one of these companies directly and paid a large amount of money to get an SSL certificate. Thankfully (at least for my wallet), these days they sell what are called “Intermediate” certificates to other, smaller, companies.
Basically the intermediate certificate is like the one you get for your web server, saying that such-and-such company has done something to verify that you are who you say you are2 and they think you can be trusted. The intermediate certificate, however, also lets this new, smaller, company issue certificates to other people. Because they have been “certified” as “trusted” by the big name “root” CA, they are now authorized to certify you as owning monkeypox.com…
So you end up with a “chain” of trust: The root CA trusts the Intermediate CA, who in turn trusts you.
The root CA doesn’t want to just hand out copies of its certificate, in case it turns out that the Intermediate CA gets hacked or wasn’t quite as trustworthy as they thought, so you have to include this chain of trust with your certificate any time you send it to a web browser so that it can track back up the chain of trust until it gets to a “root” CA that is in its known list of ones it should trust. If you don’t get this chain right you’ll get the dreaded “Untrusted certificate” warning in your web browser.
Creating the Chain
In Apache there are three configuration directives you usually include: SSLCertificateFile
, indicating the file the certificate you got from your CA is in; SSLCertificateKeyFile
, indicating the private key that you generated to go with it; and SSLCertificateChainFile
, which includes all the certificates up the chain of trust to whichever root CA is trusted by browsers.
In Nginx, the process is simplified. Instead of specifying a different chain file, you simply include the chain of trust with your certificate.
Depending on which CA you have used, they may provide a single file that’s already chained together, or they may provide multiple certificates along the way. With StartSSL, who I use for all of my certificates, you’ll get two different ones you need to include: their intermediate certificate (either a class1 or a class2, depending on whether you’ve got a free certificate or a paid one) and the upstream CA that issued their certificate.
To create your chain file, you simply need to concatenate all of these certificates together in ascending order of trust — from your server certificate, all the way up to the root CA. You can do it all with one command once you’ve got all your certs ready:
cat domain.com.crt subl.class2.server.ca.pem ca.pem > domain.com.pem
And out pops your domain.com.pem
unified chain file to feed into Nginx’s ssl_certificate directive when you’re configuring your vhost.