November 26, 2020

I run my blog on Docker, with Nginx and MariaDB

I run my  blog on Docker, with Nginx and MariaDB

This post explains how to run a Ghost blog with Nginx as a frontend load balancer and a MariaDB database backend using docker.

In this blog post, I will describe how I set up my blog using:

Background

I have been wanting to start my personal blog for a while. And after weighing the pros and cons of the different options, I have finally decided to use Ghost for my personal blog, running on a cloud VM on Google cloud.

Although ghost.org offers fully managed Ghost infrastructure, it was too expensive for a personal blog as the pricing starts from 29$/month. Besides, I really like getting my hands dirty so I also opted most of the one click installations.

I have decided to use Docker to run the blog stack (Ghost + MariaDB + Nginx) to be able to spin up the blog easily, and also to be able to replicate the same setup locally or anywhere else when needed.
In order to achieve this, I have created the khan/docker-ghost github repository to make it easier to deploy the blog.

Register a domain name

First you need to choose and register a domain name for your blog. There are multiple domain name registrars to choose from such as GoDaddy, namecheap or names.co.uk.
I chose to register my domain with names.co.uk because that's where I get free for first year. GoDaddy also offer £0.99 for first year but you have to pay for 2 years(depends on the domain name).

Provision a cloud instance

I chose to deploy the stack in Google cloud platform as its give $300 free credit for a year. Since this is just personal blog, I wasn't expecting much traffic so their E2 compute instance would be sufficient.

Pre-requisites

Since everything will be running on Docker, the only dependencies needed are docker and docker-compose which they can be installed using the command below

$ sudo apt install docker docker-compose
Install docker & compose

You also need to make sure that your non-root user is in the docker group to be able to run docker commands:

$ sudo usermod username -aG docker
Add user to docker group

Preparing the environment

First, you need to clone the github repository on your machine:

$ git clone https://github.com/khan5217/ghost.git
Clone git repository

The .env files provided in the github repository contains default configuration which can be used for running ghost locally. However, for running a public blog it must be changed accordingly.

# Tag used for the ghost docker image
export GHOST_IMAGE_TAG=latest

# Tag used for the MariaDB docker image
export MARIADB_IMAGE_TAG=latest

# Configure the blog url in ghost
export BLOG_URL=http://127.0.0.1

# Root password used for MariaDB
export MYSQL_ROOT_PASSWORD=password

# User password used by ghost to connect to the database
export MYSQL_PASSWORD=password

# Host folders used by the containers
export MYSQL_HOST_PATH=~/mariadb_data
export GHOST_HOST_PATH=~/ghost
export NGINX_HOST_PATH=~/nginx

# Exposed host ports
export NGINX_HTTP_PORT=80
export NGINX_HTTPS_PORT=443
.env file

The environment variables defined above are used by docker-compose to configure the Docker containers during (re)creation:

 version: '3.3'

services:
  mariadb:
    image: mariadb:${MARIADB_IMAGE_TAG}
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ghost
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_DATABASE: ghost_production
    restart: always
    volumes:
      - type: bind
        source: ${MYSQL_HOST_PATH}
        target: /var/lib/mysql

  ghost:
    image: ghost:${GHOST_IMAGE_TAG}
    environment:
      url: ${BLOG_URL:-http://127.0.0.1}
      database__client: mysql
      database__connection__host: mariadb
      database__connection__database: ghost_production
      database__connection__user: ghost
      database__connection__password: ${MYSQL_PASSWORD}
    depends_on:
      - mariadb
    restart: always
    volumes:
      - type: bind
        source: ${GHOST_HOST_PATH}
        target: /var/lib/ghost/content

  nginx:
    image: nginx
    restart: always
    ports:
      - "${NGINX_HTTP_PORT}:80"
      - "${NGINX_HTTPS_PORT}:443"
    volumes:
      - type: bind
        source: ${NGINX_HOST_PATH}
        target: /etc/nginx/conf.d/
docker-compose.yaml


The folders are created by default under the home directory, and this default Nginx configuration would be used:

server {
	server_name _;
	listen 80 default_server;

	location / {
		proxy_pass	http://ghost:2368;
	    proxy_set_header    X-Real-IP $remote_addr;
	    proxy_set_header    Host      $http_host;
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

	}
	server_tokens off;
}
nginx default configuraiton

Deploying

In order to deploy ghost, you just need to run the run.sh script provided in the github repository:

$ cd docker-ghost/

# You need to provide the file path for the env file
$ ./run.sh 
This script takes exactly 1 argument
Usage: ./run $ENV_FILE_PATH

$ ./run.sh .env
Sourcing .env
Deploying Ghost with the following configuration:
Blog URL: http://127.0.0.1
MySQL user password: password
MySQL root password: password
Ghost host data folder: /home/user/ghost
MySQL host data folder: /home/user/mariadb_data
Nginx host config folder: /home/user/nginx
HTTP port: 80
HTTPS port: 443
Confirm the deployment? (Y/N): y
Creating host folders...
Deploying...

Creating network "blog_default" with the default driver
Creating blog_nginx_1 ... 
Creating blog_mariadb_1 ... 
Creating blog_nginx_1
Creating blog_mariadb_1 ... done
Creating blog_ghost_1 ... 
Creating blog_ghost_1 ... done
Running the deployment

You can see that the containers are now up and running:

$ docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                      NAMES
ed066dec79d0        ghost:latest        "docker-entrypoint.s…"   4 weeks ago         Up 2 days           2368/tcp                                   blog_ghost_1
f8a48894850a        nginx               "/docker-entrypoint.…"   4 weeks ago         Up 2 days           0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   blog_nginx_1
d848ea92c849        mariadb:latest      "docker-entrypoint.s…"   4 weeks ago         Up 2 days           3306/tcp                                   blog_mariadb_1
Checking the status of the containers

By navigating to your VM's public IP address or to http://127.0.0.1 (if you are running ghost on your local environment), you should now be able to access your new ghost blog: