Skip to content

Infra / Ops

How to Add SSL to Your DigitalOcean Ghost Blog Using StartSSL

Securing a self-hosted Ghost blog on DigitalOcean end to end with a free StartSSL certificate and nginx.

8 min read
  • ssl
  • nginx
  • ghost

Web Security (view full size, opens in a new tab)

Digital Ocean is a wonderful cloud server provider with fast speeds and low costs that are perfect for developers interested in spinning up servers for a short amount of time for testing or for users interested in their available one-click application installations which exceed what's available by larger providers. Myself, I chose Digital Ocean because of the sheer speed and simplicity to develop with them after being told about them from a friend. While I am not endorsed by them, or paid, or anything, I would appreciate if you are considering trying them out to use my referral link. Enough marketing stuff let's jump into today's topic.

Creating a Ghost Blog on Digital Ocean

First things first we need a server to setup SSL on. We can set up a new droplet, or server instance, quickly and easily. Simply log into DigitalOcean, click the green Create button over the left menu, and you will find yourself at the Create Droplet page.

This is where we make the decisions about where our server will live, how powerful it will be, etc.

First, we enter a hostname, this is just a friendly name for the computer. It must be alphanumeric, periods, or dashes though. A valid hostname for example would be Ghost-Blog or Ghost.Blog while Ghost Blog would not be a valid hostname because it has a space.

Second, choose how powerful a machine you would like. If you don't have a ton of traffic, I use the 512MB / 1 CPU, 20 GB SSD, 1 TB transfer size and I have never come close to truly taxing this machine, but your needs may be different.

After selecting what size machine you would like, select a region for the server. It is best to choose either a location close to you or close to your primary users to ensure the fastest possible speeds. For me, this is usually one of the New York locations.

Following the locations is where we select what we would like installed on our machine. Click on the Applications tab and select the Ghost 0.5 on Ubuntu 14.04. This image will install everything you need to have a working Ghost blog on Ubuntu including an IPTables firewall and NGINX server.

Lastly, select any SSH keys you would like DigitalOcean to install on the server for you at creation and enable any settings such as IPv6 that you may want.

Once you are ready, click the large green Create Droplet button at the bottom of the page to begin.

Once the droplet is ready, you will be presented with a control page for your new droplet which tells you the IP Address, size of the droplet, and much more.

Authenticating with StartSSL

For the sake of simplicity in this tutorial I will be making a few assumptions:

  1. You have setup NGINX and your ghost config.js file to use your domain name of choice. If this is something you would like me to cover, I will happily cover this another day.
  2. Your NGINX configuration is located in /etc/nginx/sites-enabled/ghost. This file in your specific case may be in a different directory such as /etc/nginx/sites-available/ghost or /etc/nginx/conf.d/default.conf.

With NGINX setup to use your domain name let's begin setting up SSL. First thing we need to do is open up Google Chrome and navigate to StartSSL.

StartSSL Page — August 2014 (view full size, opens in a new tab)

On this page, click the StartSSL Free (Class 1) button on the top left of the graphic. This will bring you to a page explaining what the Class 1 certificates offer to you. Click Control Panel in the top right of the page to begin creating your SSL certificate.

Next, click Express Lane to get started right away. You will be asked for personal information which is included in your certificate including name, address, phone number and email address. Click Continue once you have filled in the information.

A registration code will then be sent to your email address provided. Enter that code in the box via copy and paste (to prevent typos) and click Continue.

You then will have to generate a private key. Select High Grade for maximum security. It will then ask you to install the certificate in your browser. So click the Install button. This may take a few minutes depending on your browser.

Verify Domain Ownership

After we have secured our browser, we now begin setting up our domain. Enter the domain name that you would like to add SSL to in the box and click Continue.

Next, select the email address you would like StartSSL to send verification to and click Continue. You will get an email with a confirmation number much like you did before. Copy and paste this in and click Continue. You have now successfully verified ownership of the domain.

Generating the SSL Certificates

Now it's time to generate our actual certificates starting with our private key. Here, we will have to enter a Key Password, which allows us to safely copy the key over the internet to our server for decryption on that end with this password. For this reason, you must not lose this password!

Next, select a Key Size of 4096 (High) and a Secure Hash Algorithm of SHA2 (Advanced). While this has compatability issues with older machines, I hope you are using one that is not. You shouldn't compromise your users' security for your convenience.

Lastly, click Continue. The site will then generate the private key. Open a text editor of your choice such as Sublime Text and copy and paste the textbox into a new file named ssl.key. Once you have saved this, click Continue.

Next, select the verified domain this certificate is for, click Continue then add a subdomain you would like on the certificate. I recommend putting www in that so your certificate supports connections with www.[YOURDOMAINNAME].com. Click Continue.

Continue through the wizard saving the files as the instructions say. Once you are done you should have 4 files:

  • ca.pem
  • ssl.crt
  • ssl.key
  • sub.class1.server.ca.pem

If you are missing the ca.pem or the sub.class1.server.ca.pem file, that is OK we can get those together.

First copy these files to your web server through FTPS or Secure Copy for maximum security.

Open an SSH session with the server using the command ssh root@[YOUR SERVER IP ADDRESS]. Assuming you have added your ssh key, this should connect cleanly and quickly.

Using the cd command, short for change directory, navigate to the folder where you have copied your files to on the server. In my example, I copied them to /etc/nginx/conf/ as that's where I will want to have NGINX reference the files when serving HTTPS requests.

Once in this folder, we need to decrypt our private key we saved. We do this with the following command:

openssl rsa -in ssl.key -out /etc/nginx/conf/ssl.key  

You will be prompted to enter your password that you gave when you created the private key. Enter this and click enter. For those new to Linux command lines, you will not see input on the command line as you type, so don't panic.

Next, we want to protect our key from others using chmod, short for change mode. Here we do the following:

chmod 600 /etc/nginx/conf/ssl.key  

In this case, we have said that only the owner can read or write the file but not execute the file. This is fine for our use.

Next, if you did not get the ca.pem or sub.class1.server.ca.pem files, we can do that now with wget.

wget http://www.startssl.com/certs/ca.pem  
wget http://www.startssl.com/certs/sub.class1.server.ca.pem  

This will download the files to our working directory (which should still be /etc/nginx/conf/). Next, because we have those two intermediate certificates, we want to unify our unique certificate with those intermediate pieces. We can do this with the cat command, short for concatonate.

cat ssl.crt sub.class1.server.ca.pem ca.pem > /etc/nginx/conf/ssl-unified.crt  

NOTE: With this, I encountered some issues with this unified certificate. After doing research, I found it was because of how the cat command was working. Please check out this NGINX SSL PEM_read_bio:bad end line tutorial I wrote to check to see if your file is correctly setup or not.

Next we want to configure our nginx server to serve HTTPS requests. To do this, we use the following command:

nano /etc/nginx/sites-enabled/ghost  

Remember that location may be sites-available, conf or conf.d instead of sites-enabled. This will depend on your specific machine and configuration though.

Your configuration file should look something like this:

server {  
    listen 80;
    server_name domainname.com www.domainname.com;

    client_max_body_size 10M;

    location / {
            proxy_pass http://localhost:2368/;
            proxy_set_header Host $host;
            proxy_buffering off;
    }
}

This is a basic NGINX server configuration. We want to add another server to handle the HTTPS requests on port 443. To do this, we add another server block like so:

# HTTPS Server

server {  
    listen 443 ssl;
    server_name domainname.com www.domainname.com;

    client_max_body_size 10M;

    location / {
            proxy_pass http://localhost:2368/;
            proxy_set_header Host $host;
            proxy_buffering off;
    }

    ssl on;
    ssl_certificate /etc/nginx/conf/ssl-unified.crt;
    ssl_certificate_key /etc/nginx/conf/ssl.key;

    ssl_session_timeout 5m;
}

Here we are saying to listen to port 443 which is the standard SSL / HTTPS port. We then use the same settings as above for the middle section, then at the end we include ssl on; for legacy NGINX situations, specify the location of the unified ssl_certificate we have made, specify the location of the ssl_certificate_key, and then lastly tell NGINX how long before a SSL session times out.

Together our configuration file should look something like this:

#HTTP Server
server {  
    listen 80;
    server_name domainname.com www.domainname.com;

    client_max_body_size 10M;

    location / {
            proxy_pass http://localhost:2368/;
            proxy_set_header Host $host;
            proxy_buffering off;
    }
}

# HTTPS Server
server {  
    listen 443 ssl;
    server_name domainname.com www.domainname.com;

    client_max_body_size 10M;

    location / {
            proxy_pass http://localhost:2368/;
            proxy_set_header Host $host;
            proxy_buffering off;
    }

    ssl on;
    ssl_certificate /etc/nginx/conf/ssl-unified.crt;
    ssl_certificate_key /etc/nginx/conf/ssl.key;

    ssl_session_timeout 5m;
}

Press control+x to exit the file, click y to say yes you would like to save the changes, then click enter/return ↩ to overwrite the file that was there.

Now, we have NGINX setup, let's restart the service to use the new configuration. We can do this with:

sudo service nginx restart  

Great! If we try to load the page though we get a timeout. This is because our one click application setup IPTables for us, which is a firewall program and we need to add support for HTTPS commands. First, lets look at the IPTables configuration by entering:

iptables -nL --line-numbers  

A standard IPTables output looking something like this should appear (modified to show an example configuration):

num  target     prot opt source               destination  
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0  
2    REJECT     all  --  0.0.0.0/0            127.0.0.0/8          reject-with icmp-port-unreachable  
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED  
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22  
5    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80  
6    DROP       all  --  0.0.0.0/0            0.0.0.0/0  

This is great but if you look at the port numbers we don't see port 443 anywhere. First, we have to add it before rule #6 or else the connection will be dropped before it evaluate checks our last rule. In this case, we would run the following command:

iptables -I INPUT 6 -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT  

We now want to save and reload IPTables with the new rules so we enter:

service iptables-persistent save  
service iptables-persistent restart  

`

Voila, now if you go to the https:// version of your domain, you should have a working SSL version up and running. Congrats!

Tag