Streamlined Docker Deployment: Hosting Ghost Blog with MySQL and Traefik

Ghost is a versatile, open-source platform designed for publishing and blogging, built on Node.js. Renowned for its sleek design and ease of use, Ghost was first released in 2013 under the MIT license.

Traefik, on the other hand, is a modern HTTP reverse proxy and load balancer specifically for microservices. It simplifies the deployment of these services by integrating seamlessly with various infrastructure components like Docker, Swarm Mode, Kubernetes, Amazon ECS, Rancher, Etcd, and Consul.

This tutorial offers a comprehensive, step-by-step guide on how to install and configure Ghost as a Docker container. We will employ the latest version of Docker CE, utilize MySQL as our database, and set up Traefik as a reverse proxy.

Prerequisites

  • Ubuntu 18.04 LTS
  • Root privileges

What We Will Do

  1. Install Docker CE on Ubuntu 18.04 LTS
  2. Setup Docker for Non-root User
  3. Install Docker Compose
  4. Configure Ghost Stack
    • Create a Custom Network
    • Create a Project Directory
    • Create and Configure MySQL Container
    • Create and Configure Traefik Reverse Proxy
    • Create and Configure Ghost Container
  5. Deploy Ghost with MySQL and Traefik
  6. Testing

Step 1 – Install Docker CE on Ubuntu 18.04 LTS

Begin by installing the latest docker-ce version for your system, obtainable from the official Docker repository.

Firstly, add the Docker GPG key and the docker-ce repository:

        curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
        sudo add-apt-repository \
          "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
          $(lsb_release -cs) \
          stable"

This command will automatically update all repositories on your system.

Now, install Docker using the command below:

sudo apt install docker-ce -y

After installation, start the Docker service and enable it to run at startup:

        sudo systemctl start docker
        sudo systemctl enable docker

Docker CE has been successfully installed on your Ubuntu 18.04 system.

Installing Docker CE

Step 2 – Setup Docker for Non-root User

To run container microservices under a non-root user, configure the user to run Docker containers and have root privileges via the sudo command.

Create a new user named ‘hakase’:

        sudo useradd -m -s /bin/bash hakase
        sudo passwd hakase

Assign the ‘hakase’ user to the ‘sudo’ and ‘docker’ groups:

        sudo usermod -aG sudo hakase
        sudo usermod -aG docker hakase

Restart the Docker service:

sudo systemctl restart docker

The ‘hakase’ user can now run Docker containers and execute sudo commands for root access.

Setup Docker for Non-root User

Log in as user ‘hakase’ and run the Docker hello-world container:

        su - hakase
        docker run -it hello-world

The result of the command is displayed below:

Test docker as non-root user

Step 3 – Install Docker Compose

We’ll install Docker Compose version 1.21 from its GitHub repository.

Download the Docker Compose binary to the ‘/usr/local/bin’ directory:

        sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

Make the ‘docker-compose’ file executable by adjusting file permissions:

sudo chmod +x /usr/local/bin/docker-compose

Verify the installation:

        docker-compose version
        docker version

Install Docker Compose

Docker Compose 1.21 with Docker CE 1.18 is now installed.

Step 4 – Configure Ghost Stack

In this step, we will set up Docker and create a docker-compose.yml file for the Ghost installation. We will establish a Docker custom network and construct a docker-compose file with three primary services: MySQL database, Traefik reverse proxy, and the Ghost blog.

Create a Custom Network

First, display existing Docker networks:

docker network ls

Create a new Docker network for the Traefik reverse proxy named ‘traefiknet’:

docker network create traefiknet

Verify the creation of the new network:

docker network ls

Create a Custom Network

The ‘traefiknet’ network has been created successfully.

Create a Project Directory

Next, create a project directory named ‘ghost’ and a docker-compose.yml file:

Log in as the ‘hakase’ user:

su - hakase

Create a ‘ghost’ directory and navigate into it:

        mkdir ghost
        cd ghost

Create the docker-compose.yml file:

touch docker-compose.yml

Create and Configure MySQL Service

The next task is setting up a MySQL container with the following specifications:

  • Use the MySQL 5.7 docker image.
  • Mount the MySQL data directory locally.
  • Run MySQL service on a private network.
  • Set up MySQL user credentials:
    • Root password: mypassword
    • Database: ‘ghostdb’, User: ‘ghost’, Password: ‘ghostdbpass’
  • The container will be named ‘mysql’.

Within the ‘ghost’ directory, create a ‘data’ directory and edit the ‘docker-compose.yml’ file:

        mkdir -p data
        vim docker-compose.yml

Add the following configuration:

services:
  mysql:
    image: mysql:5.7
    restart: always
    volumes:
      - ./data:/var/lib/mysql
    labels:
      - "traefik.enable=false"
    networks:
      - internal
    environment:
      MYSQL_ROOT_PASSWORD: mypassword
      MYSQL_USER: ghost
      MYSQL_PASSWORD: ghostdbpass
      MYSQL_DATABASE: ghostdb
    container_name: mysql

Save and exit.

Create and Configure Traefik Reverse Proxy

Now, we’ll configure the Traefik reverse proxy container.

Before editing the ‘docker-compose.yml’, create a configuration file ‘traefik.toml’:

vim traefik.toml

Add the following configuration:

# Traefik Global Configuration
debug = false
checkNewVersion = true
logLevel = "ERROR"

# Define the EntryPoints for HTTP and HTTPS
defaultEntryPoints = ["https", "http"]

# Define the HTTP port 80 and HTTPS port 443 EntryPoint
# Enable automatic redirection from HTTP to HTTPS
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]

# Enable Traefik Dashboard on port 8080 with basic authentication
# User 'hakase', password is embedded in the file
[entryPoints.dash]
address = ":8080"
[entryPoints.dash.auth]
[entryPoints.dash.auth.basic]
users = [
    "hakase:$apr1$hEgpZUN2$OYG3KwpzI3T1FqIg9LIbi."
]

[api]
entrypoint = "dash"
dashboard = true

# Enable retry for sending a request if there is a network error
[retry]

# Define Docker Backend Configuration
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "hakase-labs.io"
watch = true
exposedbydefault = false

# Let's Encrypt Registration
# Define the Let's Encrypt ACME HTTP challenge
[acme]
email = "hakase@gmail.com"
storage = "acme.json"
entryPoint = "https"
OnHostRule = true
  [acme.httpChallenge]
  entryPoint = "http"

Save and exit.

Next, create an ‘acme.json’ file to store Let’s Encrypt logs and set permissions to 600:

        touch acme.json
        chmod 600 acme.json

Now, edit ‘docker-compose.yml’ to add the Traefik service configuration:

  • Using the latest Traefik Docker image.
  • Name the container ‘traefik’.
  • Use the custom ‘traefiknet’ network, exposing HTTP and HTTPS ports.
  • Mount the Docker sock file, ‘traefik.toml’, and ‘acme.json’.
  • Define the Traefik dashboard URL and backend via Docker labels.

Edit the ‘docker-compose.yml’:

vim docker-compose.yml

Insert the Traefik service configuration:

  traefik:
    image: traefik:latest
    command: --docker
    ports:
      - 80:80
      - 443:443
    labels:
      - "traefik.enable=true"
      - "traefik.backend=dashboard"
      - "traefik.frontend.rule=Host:traef.hakase-labs.io"
      - "traefik.port=8080"
    networks:
      - traefiknet
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.toml:/traefik.toml
      - ./acme.json:/acme.json
    container_name: traefik
    restart: always

Save and exit.

Create and Configure Ghost Service

Following the setup of the Traefik reverse proxy, we proceed to create the Ghost service configuration with the specifications outlined below:

  • Use Ghost v1 on the Alpine Docker platform.
  • Mount the Ghost content directory to a local ‘blog’ directory.
  • Run Ghost on the default port using domain ‘gho.hakase-labs.io’ as configured via Docker labels.
  • Join two Docker networks: ‘internal’ and ‘traefiknet’.
  • Configure the MySQL database details provided in the MySQL container configuration.
  • Ensure Ghost starts once the Traefik and MySQL containers are operational.

Create a ‘blog’ directory and edit the ‘docker-compose.yml’ file:

        mkdir -p blog
        vim docker-compose.yml

Include the following configuration for Ghost:

  ghost:
    image: ghost:1-alpine
    restart: always
    ports:
      - 2368
    volumes:
      - ./blog:/var/lib/ghost/content
    labels:
      - "traefik.enabled=true"
      - "traefik.backend=ghost"
      - "traefik.frontend.rule=Host:gho.hakase-labs.io"
      - "traefik.docker.network=traefiknet"
      - "traefik.port=2368"
    networks:
      - internal
      - traefiknet
    environment:
      database__client: mysql
      database__connection__host: mysql
      database__connection__user: ghost
      database__connection__password: ghostdbpass
      database__connection__database: ghostdb
    container_name: ghost
    depends_on:
      - mysql
      - traefik

networks:
  traefiknet:
    external: true
  internal:
    external: false

Save and exit.

Create and Configure Ghost Service

Now, the directory structure and configuration files are set up as follows:

tree

config files

Step 5 – Deploy Ghost with MySQL and Traefik

Use the command below to build and launch the entire Ghost stack service:

docker-compose up -d

Deploy Ghost with MySQL and Traefik

Once complete, check all running services:

docker-compose ps

The expected output is shown below:

docker-compose ps

If errors arise, inspect the container logs using the following commands:

        docker-compose logs mysql
        docker-compose logs traefik
        docker-compose logs ghost

check the container log

The Ghost stack, along with MySQL and Traefik, is now operational.

Step 6 – Testing

Access the Traefik dashboard via its specified URL, for example, http://traef.hakase-labs.io/

Log in using the credentials defined in the ‘traefik.toml’ file.

Login to Traefik

The Traefik dashboard looks as follows:

Traefik dashboard

To check the Ghost installation, use the Ghost URL in your browser’s address bar. For instance, http://gho.hakase-labs.io/

You should see the Ghost homepage:

Ghost Blog running on Docker

Proceed to the admin page to set up and configure a new admin user. The admin URL is similar to: http://gho.hakase-labs.io/admin/

Click the button to create a new admin user:

Ghost installer

Complete the user details with your name, email, and password, and click the green button again.

Create admin login

Skip the member invite step for later:

Invite users

You should now access the Ghost Dashboard:

Ghost Dashboard

After creating a sample post, here is the result:

Ghost blog running in Docker container

The Ghost blog installation, alongside MySQL and Traefik Reverse Proxy in a Docker environment, has been completed successfully.

References

FAQ

What is Ghost?

Ghost is an open-source platform for publishing and blogging, leveraging Node.js for high performance and ease of customization.

What is Traefik?

Traefik is a modern reverse proxy and load balancer that simplifies deploying microservices by integrating with existing infrastructure components.

Why use Docker for Ghost?

Docker allows you to isolate applications and their dependencies into containers, ensuring consistency across multiple environments and simplifying the deployment and scaling process.

Can I use a different database instead of MySQL?

Yes, while this guide uses MySQL, Ghost can also be configured with other databases such as SQLite and PostgreSQL with appropriate adjustments in configuration files.