SSL on Nginx

This post is an attempt to document end-to-end the process of getting and installing SSL certificate on nginx server. The actual installation is pretty straight forward, its the getting the certificate part which usually trips most first time users. In this post I’m specifically referring to the filenames as used by Comodo SSL Certificate, but in the past I’ve used PositiveSSL certificate which is also issued by Comodo but has a slightly different trust chain. In general, shorter trust chains are better and will result in better performance. For a cheap certificate that cost $9/year PositiveSSL has a short trust chain of depth 3, that’s hard to beat.

Main steps for installing SSL on Nginx:

  • Generate CSR
  • Purchase SSL certificate from a vendor
  • Receive approver email
  • Approve SSL certificate
  • Vendor will email certificate
  • Create .pem file for SSL certificate
  • Install certificate on nginx

Before you can order your SSL Certificate, you must first generate a CSR (Certificate Signing Request) on your server. A CSR is an encrypted body of text. Your CSR will contain encoded information specific to your company and domain name; this information is known as a Distinguished Name or DN.

We will use openssl to generate CSR. By default Mac OS comes pre-installed with some version of openssl. For me that version installed in /usr/bin/ was ‘OpenSSL 0.9.8y 5 Feb 2013’ If you want to install openssl on your mac from scratch, I’d recommend using homebrew. Once you have installed homebrew, installing openssl involves executing this command brew install openssl

The DN (Distinguished Name) for most servers has the following fields:

  1. Country - 2 digit country code e.g. US
  2. State (or Province) - full state name e.g. California
  3. Locality (or City) - full locality name e.g. San Francisco
  4. Organization - XYZ Corp
  5. Organizational Unit - ENGR, Operations, Marketing, etc.
  6. Common Name - fully qualified domain name i.e. FQDN e.g. www.xyz.com if CSR is for wildcard certificate then (*.xyz.com)
  7. Email - email@xyz.com
  8. Challenge Password: - MySuperSecurePass
  9. Optional Company Name - xyz
mac:~ bhira$ openssl version
LibreSSL 2.8.3

mac:~ bhira$ openssl req -nodes -newkey rsa:2048 -keyout xyz_private.key -out xyz.csr
Generating a 2048 bit RSA private key
.........+++
........................+++
writing new private key to 'xyz.private_key'
-----
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:San Francisco
Organization Name (eg, company) [Internet Widgits Pty Ltd]:XYZ Corp
Organizational Unit Name (eg, section) []:Engr
Common Name (e.g. server FQDN or YOUR name) []:www.xyz.com
Email Address []:email@xyz.com

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

mac:~ bhira$ ls -l xyz*
-rw-r--r--  1 bhira  staff  1135 May  7 16:16 xyz.csr
-rw-r--r--  1 bhira  staff  1675 May  7 16:16 xyz_private.key

After purchasing the certificate from a vendor, you will receive an email from the Certificate Issuing Authority, in my case I bought the certificate from namecheap.com and the certificate was issued by Comodo Security Services. At the time of purchasing the certificate you will be asked to select an approver email (most likely the admin email associated with your domain e.g. admin@xyz.com ). In case of Comodo certificate I received an email with subject “ORDER #123456789 - Domain Control Validation for www.xyz.com ” and it contained a validation URL along with “validation code”. Click on the validation URL and when prompted copy/paste the validation code from the email. That completes the process of obtaining the SSL certificate. Hopefully you should receive the actual SSL certificate in an email after this. For me, the total time from buying the certificate, to receiving the actual Certificate in email was around 15mins. Here’s a diagram outlining the steps in the process:

SSL Flow Image

A common way of installing certificates on most servers is by using a .pem file. The .pem file is a concatenated certificate container file so that the entire certificate trust chain is contained in a single file. The order of concatenation is significant and should be the following:

  1. Primary Certificate - www_xyz_com.crt
  2. Intermediate CA Certificate - www_xyz_com.ca-bundle
  3. Root CA Certificate - AddTrustExternalCARoot.crt
mac: bhira$ ls -l
total 64
-rw-r--r--@ 1 bhira  staff   1521 May  7 16:53 AddTrustExternalCARoot.crt
-rw-r--r--@ 1 bhira  staff   2151 May  7 16:53 www_xyz_com.ca-bundle
-rw-r--r--@ 1 bhira  staff   1887 May  7 16:53 www_xyz_com.crt

mac: bhira$ cat www_xyz_com.crt www_xyz_com.ca-bundle AddTrustExternalCARoot.crt >> www_xyz_com.pem
  1. Copy www_xyz_com.pem to /etc/pki/nginx/
  2. Copy www_xyz_com_private.key to /etc/pki/nginx/
  3. chmod 400 /etc/pki/nginx/www_xyz_com_private.key
  4. Edit nginx default.conf file to use the cert
  5. sudo systemctl restart nginx
#FILE: /etc/ngingx/conf.d/default.conf
server {
    listen       80;
    listen       [::]:80;
    server_name  localhost xyz.com www.xyz.com;

    ...

    #ensure all /login requests use https
    location ^~ /login {
        return 301 https://$host$request_uri;
    }
    ...
}

server {
    listen       443 ssl;
    listen       [::]:443 ssl;
    server_name  localhost xyz.com www.xyz.com;

    #set ssl cert properties
    keepalive_timeout     70;
    ssl_certificate       /etc/pki/nginx/www_xyz_com.pem;
    ssl_certificate_key   /etc/pki/nginx/www_xyz_com_private.key;
    ssl_session_cache     shared:SSL:10m;
    ssl_session_timeout   10m;
    ...
}