Build a Blog With Digital Ocean, Ubuntu Linux, and Ghost

I looked at a few options before starting this site, including cheap shared hosting from sites like Bluehost. However, I ultimately decided to get a dedicated instance because it is so much more flexible. I can later add more sites, a VPN, Gitlab, or whatever I want.

The Tech Stack

We'll be setting up our tech stack as follows:

A Droplet from Digital Ocean is basically just a virtual server instance that runs on their cloud. They have different tiers, but for our purposes the lowest tier will suffice for $5/month. It can be upgraded at a later date if you need more resources.

Ghost is a nice platform for blogging. Wordpress is another option, but was overkill for what I wanted and also has some issues installing on the lowest tier Droplet.

Server Setup

First we need to setup our new server. Go to [Digital Ocean] and click Sign Up. You'll enter your email address and password.

Signup screen

Follow this through to add your contact and payment information. When you're done, you should be able to get to your Droplets screen. Select the "Create" drop down menu then select Droplets.

Create Droplet

The next screen is where you'll choose the image and resources for your server. We'll use Ubuntu 16.04 and the lowest tier of resources at $5/month.

Server selection

You'll also need to select your datacenter region. I went with New York.

Don't hit "Create" yet!

We still have to setup our login for the server. Time for a side note.


SSH

There is a section on the screen called Add your SSH keys. SSH is the way you'll be controlling your new server. There are two ways to authenticate when SSH-ing into a server.

Password

The fastest way to get up and going is to just not do anything with SSH keys. If you don't add SSH keys, Digital Ocean will just email you your login password that you'll input when SSH-ing into the server. This is fine but is not the most secure. If you're not worried about it, go ahead and hit create.

SSH Keys

If you want to be the most secure, you can add SSH keys. This will cause the server to recognize your computer and authenticate automatically using public key cryptography. Digital Ocean's website explains how to do this; I won't be going into it here. But do know that it is a good idea to set this up.


I'm going to assume you skipped the SSH keys. Go ahead and hit create. This takes you to your dashboard page and you should see your new server.

New server

Click on the server name and you'll be taken to the server monitoring page. Find your IPV4 address near the top of the page and take note of it. You'll need this to access your server.

IPV4

Domain Name Registration

I'm using Namecheap to register my domain name. I won't really go into detail on how to get your domain name here, because it's pretty self-explanatory. Head over to Namecheap, type in the domain name you want and buy it. They will ask you if you want a bunch of different add-ons, only one of which I chose to get.

One of the add-ons is called Whois protection. If you don't have Whois protection, anyone can run a command in their terminal whois yourdomain.com and see your contact information. Whois protection blocks that. It's free for the first year and pretty cheap after that, so I decided to take it.

The important part, after registering your domain name, is linking it to your Droplet. On Namecheap, go to your Dashboard. Select Domain List on the left side and you should see your domain.

domain list

Hit the "Manage" button and you'll see something like this:

manage screen

The section you're looking for is NAMESERVERS. Open the drop-down menu and select Custom DNS. Add the Digital Ocean name servers as shown above.

Back over at Digital Ocean, go to your Droplets page. It will list your available Droplets. On the right is a More drop-down menu. From there, select Add a domain.

add a domain

Enter a name for your domain. I used the URL that I registered. Enter @ in the HOSTNAME box. In the WILL DIRECT TO box, select your Droplet. You should be able to leave the other boxes the same. Click Create Record. Now your domain name should be linked to your Droplet.

Test this by opening terminal and pinging your domain name. You should see it redirect to the IP listed for your droplet.

ping sethmessimer.com  

Hit CTRL+C to stop the ping operation.

ping server

If you see something like that, you're in business!

Software Setup

So we have our server, now we need to install the software that will serve our blog.

Let's go ahead and SSH into it. Replace the IP below with the IP of your Droplet.

ssh root@104.236.46.462  

There will be a warning asking if you want to proceed. Type yes. You'll then enter the password that Digital Ocean sent to your email address. You'll then be asked to change your root password. Go ahead and do it. Don't lose this password! When finished, you'll be greeted by a command prompt.

Command prompt

We need to install a Ghost, our blogging platform, and Nginx, the web server that will serve the website out to visitors.

Install Nginx

At the prompt, type apt install -y nginx. If successful it will look something like this:

nginx install

Make sure Nginx is running by entering systemctl status nginx. You should see something like this:

nginx running

Hit q to exit the status message. Now we can test Nginx. Open up a web browser and enter the IP address of the server in the address bar, or better yet your domain name. You should see something like this:

nginx default

This is the default page that Nginx display when you haven't added any content to your site.

Install Ghost

Before installing Ghost we'll need to install NodeJS. In the server command prompt type the following.

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -  
apt install -y nodejs  

Make sure everything installed properly:

nodejs -v  
npm -v  

Those should output something like:

v6.11.0  
.
.
v3.10.10  

Now create a directory for Ghost, then download the .zip:

mkdir -p /var/www/  
cd /var/www/  
wget https://ghost.org/zip/ghost-latest.zip  

Now unzip it:

apt install unzip  
unzip -d ghost ghost-latest.zip  
rm ghost-latest.zip  
cd ghost/  

Configure Ghost

I'm largely pulling from a guide on Digital Ocean found here.

Ghost needs a configuration file at /var/www/ghost/config.js. By default Ghost provides an example configuration file called config.example.js. Copy this to config.js so that Ghost can use it.

cp config.example.js config.js  

The main thing we need to configure is the URL. Mail is also good to configure, but is beyond the scope of this post. Open the file for editing.

nano config.js  

In the production section, change the url to your hostname, or IP if you don't have one yet.

ghost config

Hit CTRL+x, Y, and ENTER to save and exit Nano. Now start Ghost in production mode with:

apt install python-software-properties  
npm install --production  
npm start --production  

If you get an error, it's likely because this server doesn't have enough RAM. You have two options. Either upgrade it to the $10/month instance, or add a swap file to the system. I'm cheap, so I'll add a swap file. This will help Linux page the memory to disk in case we run out (which we do during Ghost installation). Sidebar for swap file follows.


Enable Swap File

Allocate space for the swap file:

fallocate -l 1G /swapfile  

Check that it worked:

root@ubuntu-512mb-nyc3-01:/var/www/ghost# ls -lh /swapfile  
-rw-r--r-- 1 root root 1.0G Jul  9 21:17 /swapfile

Setup permissions on the swapfile so that only root can access it:

chmod 600 /swapfile  

Enable the swap:

mkswap /swapfile  
swapon /swapfile  

Check that it worked:

swapon --show  
NAME      TYPE  SIZE USED PRIO  
/swapfile file 1024M   0B   -1

We still need to make this permanent so it will survive server reboot, so we'll need to edit fstab.

cp /etc/fstab /etc/fstab.bak  
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab  

That's it! Try installing again.


You should now see the Ghost server running:

.
.
Migrations: Creating table: subscribers  
Migrations: Running fixture populations  
Migrations: Creating owner  
Ghost is running in production...  
Your blog is now available on http://sethmessimer.com  
Ctrl+C to shut down  

Hit CTRL+C to stop the server. We need to configure Nginx to point to our Ghost content. When a user connects to your site, they do so on port 80 using HTTP. Nginx is listening on port 80, but needs to forward the user to your Ghost installation. So let's configure Nginx.

First remove the default site provided by Nginx:

cd /etc/nginx/  
rm sites-enabled/default  

Now create a new site called ghost, then open it in Nano to edit:

touch /etc/nginx/sites-available/ghost  
nano /etc/nginx/sites-available/ghost  

Enter this code into the editor, replacing your_domain.tld with your domain name (or IP address):

server {  
    listen 80;
    server_name your_domain.tld;
    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:2368;
    }
}

Save and exit Nano. Now create a symlink in the sites-enabled folder so that Nginx will actually serve the site. Then restart Nginx.

ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/ghost  
systemctl restart nginx  

For security, let's create a new user that only has access to ghost. If Ghost is compromised, this should help keep the rest of the system from harm.

adduser --shell /bin/bash --gecos 'Ghost application' ghost  
chown -R ghost:ghost /var/www/ghost/  
su - ghost  
cd /var/www/ghost  
npm start --production  

Setup Ghost As Service

We need to setup Ghost to run as a service so that it will run in the background and not just in a terminal. We'll do this by creating a systemd unit file.

nano /etc/systemd/system/ghost.service  

Paste in the following text to that file:

[Unit]
Description=Ghost  
After=network.target

[Service]
Type=simple

WorkingDirectory=/var/www/ghost  
User=ghost  
Group=ghost

ExecStart=/usr/bin/npm start --production  
ExecStop=/usr/bin/npm stop --production  
Restart=always  
SyslogIdentifier=Ghost

[Install]
WantedBy=multi-user.target  

Save and exit Nano.

Now we can use systemctl to manage our Ghost service. Doing a systemctl enable [service] will cause systemd to start the service on reboot. We'll also use systemd to go ahead and start the service now.

systemctl enable ghost.service  
systemctl start ghost.service  

You should now be able to access Ghost by visiting your URL/IP address. Ghost provides a default post that you'll see when you go to your site. You can access the Ghost management site by going to www.yoursite.com/ghost.

And that's it. You can find many Ghost tutorials online to get you started on your blog. Good luck!