Simon Westphahl

Setting up HTTPS with Nginx and StartSSL

By Simon Westphahl on January 03, 2012

Update 2017-11-19: StartCom will stop issuing new certificates at the end of 2017. Please use the free Let’s Encrypt service instead.

Update 2015-06-11: The instructions for creating the CSR where updated to use SHA-2 instead of SHA-1 (thanks to Renne Nissinen for the hint)

Almost all hosting providers offer some sort of SSL certificates but most of the time they charge you a heck of a lot of money. StartSSL offers a free certificate with domain name and email validation. In contrast to CAcert the StartSSL root certificate is included in all major browsers; reads the user gets no annoying SSL warning.

Preparations

Before we can sign up for a certificate we have to generate a RSA private key. The key is needed for creating the CSR (Certificate Signing Request) and also used by Nginx later on for encrypting the connection.

$ openssl genrsa -des3 -out example.com_secure.key 4096

You will be prompted to provide a passphrase (required). The key file is secured with this passphrase but we will eventually remove this protection.

Creating the Certificate

Now we will use the private key to generate a certificate signing request which is then submitted to the CA - in my case StartSSL.

$ openssl req -new -sha256 -key example.com_secure.key -out example.com.csr

OpenSSL will ask you for some general information e.g. country code, company name, etc. to be included in the CSR.

After signing up and validating your domain at the StartSSL website you are abel to create a “Web Server SSL/TLS Certificate” with the “Certificates Wizard” on your StartSSL control panel.

Because we already generated the private key on the command line we must skip the key generation step. You can then simply submit the created CSR (copy & paste).

The signed cert will be in PEM format. We can just save the content of the displayed text box to a file with a .pem extension (e.g. example.com.pem).

We also need the class 1 intermediate certificate.

Configuring Nginx

Before we start configuring Nginx/SSL we have to make sure to remove the passphrase from our RSA key. Otherwise you have to provide the password every time Nginx is started.

$ openssl rsa -in example.com_secure.key -out example.com.key

The unencrypted private key should only be readable by the owner of the Nginx master process. Most of the time this is the root user.

$ chmod 400 example.com.key
$ sudo chown root:root example.com.key

I put all the certificate stuff in a ssl subdirectory of /etc/nginx.

For Nginx we have to concatenate the StartSSL intermediate cert with our own certificate.

$ cat example.com.pem sub.class1.server.sha2.ca.pem > example.com_chain.pem

The order is important here. According to the docs of the Nginx SSL module our server certificate must come first in the file.

HTTPS support in Nginx is now configured in a server directive like this:

server {
    listen 443 default_server ssl;
    ssl_certificate /etc/nginx/ssl/example.com_chain.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    ...
}

Additional Security

HTTP Strict Transport Security

If you run a HTTPS-only site, you should consider using HTTP Strict Transport Security (HSTS). HSTS tells a browser that the website should only be accessed through a secure connection.

# Remember this setting for 365 days
add_header Strict-Transport-Security max-age=31536000;

If you access the HTTPS version of the site, the HSTS header will be remembered by a standard compliant browser for max-age seconds. The next time you try to connect to the site using HTTP it will automatically switch to HTTPS provided that the entry has not expired yet.

X-Frame-Options

If you serve a page over HTTPS, usually you will never allow your content to be framed. This can be specified by the X-Frame-Options header.

add_header X-Frame-Options DENY;

This header can be especially useful to avoid clickjacking attacks.

See the article about securing your site on the Mozilla Developers Network for further information.