HTTPS Support

Howdy folks, If you haven’t seen already, I’ve switched over from Bluehost shared hosting with Apache to a DigitalOcean VPS with Nginx. Overall, I couldn’t be happier having this much control over my server and applications. In addition to that, I’m now glad to be serving pages to you over HTTPS, instead of HTTP.

20150417_002

 

I didn’t need a wildcard certificate, or an Extended Validation (EV) certificate, a simple SSL server certificate was enough. After browsing r/webdev, r/webhosting, and r/sysadmin, I settled on StartSSL as my Certificate Authority (CA). StartSSL offers certificates for free for 1 yr, which was perfect for my needs. Be advised, however, that StartSSL charges $24.90 to revoke a certificate. Even when Heartbleed was exposed, StartSSL refused to revoke certificates for free.

I won’t go over how to sign up for an account with StartSSL. I used this guide by Eric Mill, which made the process very easy. As a side note, a really nice feature of StartSSL is that instead of signing into their control panel with a username/password, you use a certificate. The only downside is if you lose the certificate, you’re locked out of your account forever. Again, Eric’s guide is 100% accurate, but the steps I used to generate my certificate are (condensed) below.

sudo mkdir /etc/nginx/ssl
cd /etc/nginx/ssl
sudo openssl genrsa -aes256 -out my-private-encrypted.key 2048
sudo openssl rsa -in my-private-encrypted.key -out my-private-decrypted.key
sudo openssl req -new -sha256 -key my-private-decrypted.key -out loganmarchione.com.csr
##Paste the contents of the CSR file into StartSSL's website##
##Copy the certificate they give you and save it as ssl.crt##
sudo wget https://www.startssl.com/certs/class1/sha2/pem/sub.class1.server.sha2.ca.pem
sudo wget https://www.startssl.com/certs/ca.pem
cat ssl.crt sub.class1.server.ca.pem > ~/unified.crt
sudo mv ~/unified.crt /etc/nginx/ssl
sudo chmod 644 unified.crt
sudo chown root:root unified.crt
sudo openssl dhparam -outform pem -out dhparam2048.pem 2048

A few things to note:

  • In September, both Google and Mozilla announced they will be phasing out certificates with SHA-1 based signature algorithms. Because of this, I’m using a SHA-256 based signature.
  • In addition, I’m downloading the SHA2 intermediate certificate from StartSSL. If I used the SHA1 certificate, Chrome or Firefox would complain about the encryption being “obsolete“.
  • I’m going to pre-generate a 2048-bit random parameter for DH elliptic curves. If not, the default is only 1024-bit.

 

Also, don’t forget to open your firewall for HTTPS, if you haven’t already.

sudo ufw allow "Nginx HTTPS"
sudo ufw disable
sudo ufw enable

 

Finally, update your Nginx config.

server {
        listen 80 default_server;                       #Listen on IPv4
        listen [::]:80;                                 #Listen on IPv6
        server_name loganmarchione.com loganmarchione.com;
        return 301 https://$host$request_uri;           #Redirect HTTP to HTTPS
}
server {
        listen 443 ssl spdy;                            #Listen on IPv4
        listen [::]:443 spdy;                           #Listen on IPv6

        ssl_certificate /etc/nginx/ssl/unified.crt;
        ssl_certificate_key /etc/nginx/ssl/my-private-decrypted.key;

        #Add perfect forward secrecy and prevent BEAST attacks
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK";

        #Prevent POODLE attacks
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        #Enable HSTS
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;';
        ssl_dhparam /etc/nginx/ssl/dhparam2048.pem;

        root /var/www/loganmarchione;                   #Set document root
        autoindex off;                                  #Turn off index browsing everywhere
        index index.php index.html;                     #Set indexes to include .php before .html

        location / {
        try_files $uri $uri/ /index.php?$args;
        ...MORE CONFIG HERE...
}

A few things to note:

  • I’m using a 301 permanent redirect to point HTTP to HTTPS.
  • I’m listening on IPv4 and IPv6, on both ports 80 and 443.
  • I’ve enabled SPDY support, thanks to commenter Cliff for pointing this out!
  • I’ve specified my keys, as well as some other configurations for security.
  • I’m using a more modern cipher suite, since I’m more concerned about security than backward compatibility.

 

Also, it’s a good idea to force WordPress to serveĀ admin pages over SSL by editing the wp-config.php file.

define('FORCE_SSL_ADMIN', true);

 

Finally, reload everything and you should be able to access your site over HTTPS.

sudo service php5-fpm restart
sudo service nginx reload

 

You may get a warning about mixed content, like below.

20150417_003

 

This is because we need to set our new HTTPS address in WordPress. Go to the WordPress admin dashboard, then Settings, then General. Here, add the “s” to your site address, so it reads “https”, like below.

20150417_004

 

Once you save, you’ll be forced to log out and back in. As long as you aren’t serving content (images, scripts, etc…) from other sites, you should see the green lock.

20150417_002

 

Head over to Qualys SSL Labs to test your SSL configuration. They will test your site, as well as make recommendations. You can see my test results, below.

20150417_005

 

-Logan

10 thoughts on “HTTPS Support

    • Cliff,

      Those config files are in the post, located here. This includes /etc/nginx.conf, as well as my site config file, before HTTPS was added.

  1. With the nginx-extras build you specify here, it appears that the SPDY module is not enabled. Is there a reason you chose not to use SPDY, or have you now started using it on your SSL enabled site?

    • No, I thought it needed to be included when you compiled Nginx from source, but apparently it’s built-in now. I’ll enable it tonight, thanks for the tip! Are you using it?

  2. Hi Logan. I was wondering if you could point me in the right direction to get the above setup, which forces all traffic over SSL, to allow any URL beginning with the path /wc-api/v1 to be served over regular HTTP. I’m trying to connect the WooThemes iOS App to my WooCommerce store, but their App won’t connect because it expects certain addresses to be non-ssl, and the above server config forces all to be SSL. Thanks for any help.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.