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:


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 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
I chose to register my domain with 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.


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
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=

# 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
.env file

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

 version: '3.3'

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

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

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

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


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

$ cd docker-ghost/

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

$ ./ .env
Sourcing .env
Deploying Ghost with the following configuration:
Blog URL:
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...

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 >80/tcp,>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 (if you are running ghost on your local environment), you should now be able to access your new ghost blog: