Building a Ghost Blog Server

This post acts more like a checklist of steps to complete when setting up a new Ghost Blog from a base Ubuntu installation. It focuses on doing so on a droplet provided by Digital Ocean, but could be adapted to any other provider.

Building a Ghost Blog Server

This post acts more like a checklist of steps to complete when setting up a new Ghost Blog from a base Ubuntu installation. It focuses on doing so on a droplet provided by Digital Ocean, but could be adapted to any other provider.

If you want to set up your own server with Digital Ocean and found this page useful, consider using this affiliated link for which I will receive credit to keep failedtofuncion.com up and running: Digital Ocean

When I set up this blog originally I used the One Click option provided by Digital Ocean. This is a good option as it gets you up and running quickly.

On the other hand it hides some of the initial setup, masking some of the details of what is going on under the hood. Why do I need to know about that? By choosing Digital Ocean, I am committing myself to managing the server completely: applying OS patches, application updates, managing space, etc. To do so effectively, it is good to know everything that is under the hood.

Occasionally it will be necessary to migrate the blog from an older to a newer server, perhaps for additional space or computing power, or more likely to move off an unsupported version. It is good to have knowledge of the parts involved before trying to do so. I feel strongly that if something necessary is difficult, you should try to do it as often as possible. This builds familiarity and allows you to practice and spot easier ways to do it.

One final reason is that I want to be able to spin up a test version of the site for trying out new themes or playing with some of the settings, possibly even developing my own theme. It seems like a good thing to be able to get a facsimile up and running quickly so this list will be invaluable to me in the future.

Resources

I used a number of sources in combination to build up this list of steps. I have not repeated all the details of why something is necessary, so if in doubt you can use these resources for additional information.

There are a few pages offered by Digital Ocean for the various versions of Ubuntu. When I created the server they emailed me a link to the 14.04 page even though I had set up 16.04 - go figure. Here’s both links anyway: 14.04, 16.04

The commands are merged somewhat with the instructions from the ghost installation documentation, available here: https://docs.ghost.org/docs/install

Creating and Securing a Server

Digital Ocean make this simple. Click on the create droplet button, select Ubuntu and the size and speed you want, ensure it’s on the nearest geographic location to you and click create. I’d recommend not adding SSH when creating the droplet, you can add it later. The best practice is to create a super user other than root to do administration work with. It looks like the key added at setup applies to the root user.

Once created, you should get an email with the connection details. Connect using ssh from terminal with:

ssh root@<ip address>

Create an administrator user for doing the rest of the installation:

adduser <user>
usermod -aG sudo <user>

Copy your SSH key to the server. First exit from SSH and then run the copy command. If you don’t already possess a public-private key pair, you can follow the instructions on this page.

exit
ssh-copy-id <user>@<ip address>

You should now be able to connect without entering the password. Note that you will need the password for doing all administration work that requires elevated privileges with the command sudo.

Connect again, this time as the new user

ssh <user>@<ip address>

Remove the ability to login to the server as root by SSH by changing the line PermitRootLogin yes after editing the following file:

sudo vi /etc/ssh/sshd_config

Then reload SSH:

service ssh restart

Open a new terminal and verify that you can still connect! If not undo the previous change.

Check that the firewall is set up - the following lists applications for which it is configured:

sudo ufw app list

Ensure the firewall allows ssh connections and then enable the firewall:

sudo ufw allow OpenSSH
sudo ufw enable

It makes sense do double check from a new terminal that you can still log on before going much further.

Another precaution is to disallow connections via ssh with password. That means that the user has to use a private key. Edit the following file:

sudo vi /etc/ssh/ssh_config

Change the line with PasswordAuthentication so that it looks like this:
PasswordAuthentication no

And then reload the ssh daemon:

sudo systemctl reload sshd

Before disconnecting, test that you can connect with a new terminal window.

Ghost installation

Update and install Nginx:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install nginx
sudo ufw allow 'Nginx Full'

The next step will require a database root password to be set - do not skip this step:

sudo apt-get install mysql-server

Get the repository for and install Node.js

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

Install Ghost CLI and test it is working:

sudo npm i -g ghost-cli
ghost help

Install Ghost via the CLI (use the user created above):

sudo mkdir -p /var/www/ghost
sudo chown [user]:[user] /var/www/ghost
cd /var/www/ghost
ghost install

The installation prompts for a range of inputs with the default usually sufficing; the following have no default:

  1. The URL for the site
  2. MySQL user - root
  3. MySQL password - as entered above

Say “yes” to Nginx and, if the domain is setup, also say “yes” to creating a SSL.

Note that some of the settings above could be entered differently for a test site compared to a new production site. Also if something fails (for example, if the domain name is not yet pointing at the server IP then the SSL generation step will fail) then the installation will not complete. You can restart later with sudo ghost setup once the problem has been fixed.

The last option is to start up ghost - this can be done with sudo ghost start later if you are not ready to bring up the service yet.

Cloudflare

One of the options is to setup the SSL using Let's Encrypt. This will only work if the domain name for the website has been correctly routed to the new server. The steps involved (including using Cloudflare’s content delivery network) are:

  1. Register a domain name
  2. Add the domain to Cloudflare - there’s “Add Site” button at the top navigation bar.
  3. Set up the DNS - an A record pointing to the new IP address and a CNAME record redirecting www traffic to the A record at a minimum.
  4. Change the settings on the domain registration site to point to the Cloudflare name servers
  5. Wait - the above can take up to forty eight hours
  6. Verify the domain name no longer points to a parking web page

Secure the MySQL installation

Run the following and select yes at each prompt. It removes the ability to remotely login as the root user, protecting against a dictionary attack. It also removes test accounts and generally tightens up security.

sudo /usr/bin/mysql_secure_installation

Sign in to Ghost

It would be a good idea to sign into ghost now to verify it works and also as the first login creates the owner. Go to the website and you should see the default Ghost home pages; append /ghost to the URL and it will prompt you to create an account and invite users.

Disable the Default Nginx Site

Nginx places a default site in /var/www/html with a short welcome message. This will only be visible if you connect to the server with the IP address from a browser, but it's best to disable it.

sudo rm /etc/nginx/sites-enabled/default 
sudo service nginx reload

Now connecting with the IP address should bring back the Ghost blog.

If at First You Don’t Succeed

If all else fails, simply delete the droplet and start again. Don’t leave it around incurring cost. Don’t waste too much time trying to fix something that went horribly wrong. Make sure to backup any posts first.