Setting up SSL with nginx (using a NameCheap EssentialSSL wildcard certificate on DigitalOcean)
Brief notes from my experience in setting up nginx on a DigitalOcean droplet running Ubuntu 14.04 LTS to use SSL with a Comodo EssentialSSL wildcard certificate from NameCheap.
On your development machine
(You could do this on the server and skip the copying the keys section, below, but I wanted to have a backup of my keys and certificates.)
First off, create a private key — a 2048 bit key should suffice for the time being:
openssl genrsa 2048 > key.pem
While we’re in the command line, let’s also create a key to use when implementing perfect forward secrecy:
openssl dhparam -out dhparams.pem 2048
Next, create the signing request:
openssl req -new -key key.pem -out csr.pem
Now, buy an EssentialSSL wildcard certificate from NameCheap and copy and paste the contents of the csr.pem
file to the form on NameCheap when prompted to following the purchase.
Ask for your certificate to be emailed to you. It should arrive in a little while (mine didn’t and I had to contact support and upload a file to my domain after which the support tech provided me the file in the online chat).
Create a certificate bundle
You will get a zipped folder with the following files:
STAR_yourdomain_ext.crt
COMODORSADomainValidationSecureServerCA.crt
COMODORSAAddTrustCA.crt
AddTrustExternalCARoot.crt
To use these, you have to create a certificate bundle. If Comodo/NameSecure respected the limited time that people have on Earth, they’d create this for you. Apparently, they don’t, so we have to run the following command to do it:
(Note: substitute STAR_yourdomain_ext.crt
with the actual name of the file that was in your specific download.)
cat STAR_yourdomain_ext.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > bundle.cer
On your server
Now, you need to place the private key and your certificate bundle on your server.
I am assuming that you have already installed nginx and the instructions below are from an Ubuntu 14.04 LTS installation on Digital Ocean so your mileage may vary. (If you need help in installing nginx on Digital Ocean, here is a tutorial to help you install nginx on Ubuntu 14.04 LTS)
Copying the keys
To copy the keys:
- ssh into your server
sudo mkdir /etc/nginx/ssl
sudo nano /etc/nginx/ssl/bundle.cer
and copy the bundle.cer file’s contents from your development machine and paste it into this file. Save & exit (Ctrl+X
; Yes).sudo nano /etc/nginx/ssl/key.pem
and copy the key.pem file’s contents from your development machine and paste it into this file. Save & exit.- Protect that directory:
sudo chmod 600 /etc/nginx/ssl
Update: the way I manage this now is that I’ve put the /etc/nginx
directory under Git and I simply git pull
and restart nginx to update the configuration. Much easier than messing with nano, etc., on the server, and much less brittle/risky.
Configuring your site
The following steps will set up your site to be served over SSL, with any non-SSL requests (with or without a www prefix) forwarded to the SSL server. (Solution courtesy of Davis.)
(Note: on my machine, nginx is installed at /etc/nginx).
- ssh into your server
sudo nano /etc/nginx/sites-available/default
to edit the configuration for the default site.- First, let’s create the http server on port 80 and make it forward all requests to https:
# # Rewrite http requests to https # server { listen 80; server_name yourdomain.ext; return 301 https://yourdomain.ext$request_uri; }
- Next, let’s create the rules to forward all requests to www.yourdomain.ext to https://yourdomain.ext:
# # Rewrite requests for http://www.yourdomain.ext to https://yourdomain.ext # server { listen 80; server_name www.yourdomain.ext; return 301 https://yourdomain.ext$request_uri; }
- Finally, let’s create the actual https server (for this, I edited the default domain server. I’m only showing the top of the definition — only the bits that I altered:
server { listen 443 ssl; listen [::]:443 ipv6only=on; ssl_certificate ssl/bundle.cer; ssl_certificate_key ssl/key.pem; root /path/to/the/root/of/your/site; index index.html index.htm; # Make site accessible from http://localhost/ server_name yourdomain.ext; location / { # More lines…
Perfect forward secrecy and HSTS
To get an A+ on SSLLabs (because you know you want to), you need to add perfect forward secrecy and HTTP Strict Transport Security (HSTS). The former is based on the cipher suites used and the latter simply requires one line of configuration code:
server {
# …
# Perfect forward secrecy
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparams.pem;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
# …
}
The explanation for the HSTS line, from Scott Helme:
The ‘max-age’ values specifies how long, in seconds, you want the client to treat you as a HSTS host. That is, how long you want them to contact you using HTTPS exclusively. The value I’m using here is 1 year and each time the client visits my site and receives the header, the timer is reset back to a year. Assuming your browser is HSTS compliant, after the first page load over HTTPS, you will no longer be able to communicate with me via HTTP, the browser will prevent it. The ‘includeSubdomains’ directive is fairly self explanatory. I don’t have any sub-domains on my blog but I still issue the directive as a precaution. If you want the HSTS policy to be enforced on all of your sub-domains, include the directive in your header.
(Thanking Tom Morris for his help with the HSTS bit.)
Fixing the Poodle
Due to the Poodle vulnerability in SSL 3.0, you must disable SSL 3.0. In your server block add:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Updating your nginx.conf
There’s just one more thing to do before we can restart the server:
- Edit the nginx.conf file:
sudo nano /etc/nginx/nginx.conf
- Uncomment the line:
server_names_hash_bucket_size 64;
That’s it. Now restart nginx with:
sudo service nginx reload
And check that it has restarted:
(Don’t ask me why you don’t get a friendly message telling you it did or a helpful error if it didn’t; in an ideal world, you should.)
ps aux|grep nginx
If all is well, you should see multiple lines of output similar to:
… nginx: master process /usr/sbin/nginx
… nginx: worker process
… nginx: worker process
… nginx: worker process
… nginx: worker process
If all is not well, check the error log for possible reasons:
sudo tail /var/log/nginx/error.log
Troubleshooting
You should not run into these issues if you followed the instructions, above, but I am including them here because I ran into them while stumbling my way towards the solution and it should help others who are stuck to find this page.
could not build the servernameshash, you should increase servernameshashbucketsize: 32
You forgot to uncomment the line raising the names_hash_bucket_size
in nginx.conf. What’s a names_hash_bucket_size
, you ask? An implementation detail that we probably should never have had to deal with is the first answer that comes to mind.
To fix this, follow the instructions in the Updating your nginx.conf section, above.
Incorrect certificate bundle
If you create your certificate bundle incorrectly, you will get the following error:
SSL_CTX_use_PrivateKey_file("/etc/nginx/ssl/aralbalkan.com.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
You can check whether your certificate file is correctly formed by running the following command:
(Substitute PRIVATE_KEY_FILE_PATH
with the path to your private key file and CERTIFICATE_BUNDLE_FILE_PATH
with the path to your certificate bundle file.)
diff <(openssl rsa -in PRIVATE_KEY_FILE_PATH -modulus -noout) <(openssl x509 -in CERTIFICATE_BUNDLE_FILE_PATH -modulus -noout)
If there is any output, this is the problem and you should follow the instructions in the Create a certificate bundle section, above, to fix it.
I’ve installed nginx but where is everything?
Once you’ve installed nginx, here are the main folders you need to know:
nginx’s configuration files are in:/etc/nginx
nginx config file:/etc/nginx/nginx.conf
The default site is served from:/usr/share/nginx/html
Default site config info:/etc/nginx/sites-available/default
How to I start, stop, and restart nginx?
To start nginx:
sudo service nginx start
To restart nginx:
sudo service nginx reload
To stop nginx (note, restart is safer than start + stop as it will not stop it if there is an error in your config)
sudo service nginx stop