logo image Faisal Rahman
ID EN
My profile picture taken in the summer Faisal Rahman

Installing Ghost in Docker on DigitalOcean


As I previously described in How This Blog Was Made, this blog is built on the Ghost platform (ghost.io) running inside a Docker container (docker.io). I chose this method for its convenience and modularity, and the installation process is straightforward. Here I will outline the steps I took to build this blog.

First of all, as stated in the title, we will be using a hosting server on DigitalOcean. If you want to try it right away, you can rent a droplet with the most economical option ($5/month) with the first two months free here. The droplet option I use in this article is based on Ubuntu 16.04.2; you can adjust accordingly if you are using a different option.

After the droplet is created, SSH into that droplet and then install Docker.

Preparing Docker

Installation

Add the official Docker repository for Ubuntu 16.04 with the following commands.

$ sudo apt-get update
$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
$ sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main'
$ sudo apt-get update
$ sudo apt-get install -y docker-engine

Make sure that the apt repository for docker-engine points to apt.dockerproject.org.

$ apt-cache policy docker-engine
docker-engine:
  Installed: (none)
  Candidate: 1.11.1-0~xenial
  Version table:
     1.11.1-0~xenial 500
        500 https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages
     1.11.0-0~xenial 500
        500 https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages

If everything looks correct, install Docker.

$ sudo apt-get install -y docker-engine

Preparing the Ghost Image

The Ghost container is available in the public repository. All we need to do is pull it to our server.

docker pull ghost

After the pull process is complete, we could technically already run Ghost by creating a container based on that ghost image. However, for a production-level implementation we need to perform further configuration.

Configuring Ghost

The core Ghost platform we will create, along with all its dependencies, runs encapsulated inside a Docker container. To be able to inject configuration and content into the container, we will mount a directory containing Ghost’s configuration and content from our server into the relevant directory inside the Ghost container.

Let’s create a directory to store Ghost’s files. This directory can be anywhere, but for simplicity let’s create it in the home directory.

$ mkdir ~/ghost
$ cd ~/ghost

Download the Ghost installation zip file and extract the content directory and the config.example.js file into our configuration directory. Don’t forget to rename config.example.js to config.js.

$ wget https://ghost.org/zip/ghost-latest.zip
$ unzip ghost-latest.zip "content/*"
$ unzip ghost-latest.zip "config.example.js" -d content
$ mv content/config.example.js content/config.js
$ rm ghost-latest.zip

After that, edit the config.js file in the production section.

production: {
  url: 'https://icalrn.id', // fill in this config with your domain
  paths: {
      contentPath: path.join(process.env.GHOST_CONTENT, '/') // change to this
  },
  // ...
}

Ghost configuration is complete. Now it’s time to start the Ghost container that uses this configuration.

Starting the Ghost Container

To create a container in Docker, we will use the docker run command.

We will give the container a name with the --name option. Naming is optional; if we don’t provide a name, Docker will generate one for our container.

Next we will use the -v option to volume-mount our configuration directory into that container. For example, the configuration directory I created is at /home/icalrn/ghost/content, so I map it to /var/lib/ghost with the option -v /home/icalrn/ghost/content:/var/lib/ghost.

We also need to publish the port to be mapped so that it can be accessed from outside the Docker environment with the -p option. Ghost runs on port 2368 by default. We want to map it to port 80 on our server to automatically direct HTTP requests to Ghost. So, we can provide the option -p 80:2368.

We also need to provide an environment variable so that Ghost and Node inside the container run in production mode with the -e option. Finally, we will run the container in detached mode so that our terminal doesn’t have to keep watching the running container with the -d option.

Let’s go!

$ docker run --name blog -v /home/icalrn/ghost/content:/var/lib/ghost -p 80:2368 -e NODE_ENV=production -d ghost

You can visit your domain in your favorite browser to test whether Ghost has been successfully installed. Hope this is helpful!