Start A Blogging Website Using Ghost and Secure It With Traefik

Start A Blogging Website Using Ghost and Secure It With Traefik
In this article, I will show how you can easily start a blogging website like mine – Narasimman Tech using Ghost and secure it using Traefik on a Docker Container.

Ghost is a very popular open-source blogging platform. It is an alternative to WordPress and has many inbuilt features like native SEO, Membership, Paid Subscriptions, and more whereas on WordPress they are paid plugins.

We will also use another software called Traefik. It is also a popular open-source cloud-native application proxy, API Gateway, Edge-router, and more. We use Traefik to secure our website using an SSL certificate obtained from LetsEncrypt. Once deployed, Traefik can automatically manage your certificates and renewals.

If you are a software developer or working in any tech industry, you probably might have heard of Docker. Docker is an open platform for developing, shipping, and running applications. With Docker, you can manage your infrastructure in the same ways you manage your applications.

1. Getting a Domain Name

The internet is rich with opportunities to create a business or blog on free or paid to host sites or social media. It’s not necessary to have your domain to get started, you can use the IP address. But I strongly recommend you buy a domain. Having a domain name, especially with the very familiar .com extension, can help your audience remember your website, and be easily searchable. Get a cheap domain at NameCheap. Use this link to purchase a .com domain for just $0.99!

Get a 2-year .COM Discount | .COM Promo Codes - Namecheap
Get a.COM promo code and save money when you register for 2 years. Plus, enjoy free email trial, free privacy protection, and 24/7 expert customer support with every registration.

Once you get a domain, use Cloudflare to set up your DNS. Here’s the official article:

How to set up DNS records for your domain in Cloudflare account - Hosting - Namecheap.com
Learn more about How to set up DNS records for your domain in Cloudflare account. Find your answers at Namecheap Knowledge Base.

2. Setting up your Cloud Instance

It is easy to use Ghost itself to host your website, which starts from $9 per month. But self-hosting on your system or cloud providers like AWS, Digital Ocean, Linode, etc., is cheaper, and you get full control of your data. I use DigitalOcean to host my website - Narasimman Tech, it is easy and cheap to set up. I recommend you to use DigitalOcean as well. It’s just $5 to launch a Droplet, you can use the link below to get a $100 credit.

DigitalOcean Referral Badge

To create a Droplet on DigitalOcean and install Docker, take a look at the official blog post that I’ve linked at the bottom of this page in the Additional Resource and Reference section or you can watch my video below.

Before you start to create a DigitalOcean Droplet, set up SSH keys. I will add a link to how to can set up SSH Keys. Refer to the Additional Resources and References below.

3. Setting up Docker

  • After setting up Docker on your new DigitalOcean Droplet, copy the public IP and ssh into it as the root user from the terminal.
ssh root@<IP address of the Droplet>
  • We will be running our services in a Docker Swarm Environment. If you don’t know what is Docker Swarm, check the link below.
Swarm mode overview
Docker Engine swarm mode overview
  • To start a Docker Swarm Environment run,
docker swarm init

This creates a new Swarm Environment and this becomes your manager node. You can add a new Droplet as a worker node, to scale up your services, but that’s beyond the scope of this tutorial.

Creating Required Configuration Files and Directories

  • Create a folder called my website or anything you want and change the directory to the newly-created directory.
mkdir website

cd website
  • We have to create a couple of files and directories to store Traefik configuration files and our SSL keys:
    – Create a new directory called ‘data’ and change the directory into it.
mkdir data

cd data
  • Inside this directory, create two new files called traefik.yml and acme.json change the permission of acme.json to 600.
touch traefik.yml acme.json

chmod 600 acme.json
  • Open the file using any editor. Note: My favorite editor is Vim.
nano traefik.yml
  • Paste the following code in the traefik.yml file.
api:
  dashboard: true
  debug: true
serversTransport:
  insecureSkipVerify: true
entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure

  websecure:
    address: :443
    http:
      middlewares:
        - secureHeaders@file
        - nofloc@file
      tls:
        certResolver: letsencrypt
        domains:
          - main: yourdomain.com
            sans:
              - "*.yourdomain.com"

pilot:
  dashboard: false

providers:
  docker:
    swarmMode: true
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /configurations/dynamic.yml

certificatesResolvers:
  letsencrypt:
    acme:
            #caServer: https://acme-staging-v02.api.letsencrypt.org/directory
      email: youemail@email.com
      storage: acme.json
      keyType: EC384
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

We have to change a few variables,

  • Change yourdomain.com to the domain you own.
          - main: yourdomain.com
            sans:
              - "*.yourdomain.com"
  • Create a new directory called configurations and change the directory into it. Inside this directory, create a new file called ‘dynamic.yml’ and copy-paste the following lines.
mkdir configurations

cd configurations

touch dynamic.yml

nano dynamic.yml
# Dynamic configuration
http:
  middlewares:
    nofloc:
      headers:
        customResponseHeaders:
          Permissions-Policy: "interest-cohort=()"
    secureHeaders:
      headers:
        sslRedirect: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 31536000

    # UserName : admin
	# Password : qwer
    user-auth:
      basicAuth:
        users:
          - "admin:$apr1$tm53ra6x$FntXd6jcvxYM/YH0P2hcc1"

tls:
  options:
    default:
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
      minVersion: VersionTLS12

Note:

  • The default username is ’admin’ and the password is ‘qwer’
We are close to launching our new Site!!

Setting up Traefik and Ghost

  • Now go back to our main directory, i.e., ‘website’ directory in my case, which we created at first.
cd ~/website
  • Now create a file called docker-compose.yml
  • Use any editor and open the docker-compose.yml file.
touch docker-compose.yml

nano 
  • Paste the following in the editor you opened.
# Traefik, Ghost, and MySQL
version: '3.3'

services:
  traefik:
    image: traefik:latest
    networks:
      - traefik
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/configurations:/configurations
    environment:
      - CF_API_EMAIL=
      - CF_DNS_API_TOKEN=
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]
      labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik"
      - "traefik.http.routers.traefik-secure.entrypoints=websecure"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.yourdomain.com`)"
      - "traefik.http.routers.traefik-secure.service=api@internal"
      - "traefik.http.services.traefik-secure.loadbalancer.server.port=8080"

  ghost:
    image: ghost:4-alpine
    depends_on:
      - mysql
      - traefik
    networks:
      - traefik
      - backend
    volumes:
      - ghost_data:/var/lib/ghost
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: mysql
      database__connection__user: root
      database__connection__password: secretpassword
      database__connection__database: ghost
      # this url value is just an example, and is likely wrong for your environment!
      url: https://yourdomain.com
      # contrary to the default mentioned in the linked documentation, this image defaults to NODE_ENV=production (so development mode needs to be explicitly specified if desired)
      #NODE_ENV: development
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]
      labels:
        - "traefik.enable=true"
        - "traefik.docker.network=traefik"
        - "traefik.http.routers.ghost-secure.entrypoints=websecure"
        - "traefik.http.routers.ghost-secure.rule=Host(`yourdomain.com`)"
        - "traefik.http.routers.ghost-secure.service=ghost"
        - "traefik.http.services.ghost.loadbalancer.server.port=2368"

  mysql:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: secretpassword
    networks:
      - backend
    volumes:
      - sql_data:/var/lib/mysql
    deploy:
      placement:
        constraints: [node.role == manager]

networks:
  traefik:
    external: true
  backend:
    external: true

volumes:
  ghost_data:
    external: true
  sql_data:
    external: true
  • Don’t close the file yet, we have to change a few parameters.

Change the Following:

  • Replace ‘traefik.yourdomain.com; with a subdomain.
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.yourdomain.com`)"
  • Replace ‘secretpassword’ with a new password.
database__connection__password: secretpassword
  • Replace ‘https://yourdomain.com' with your URL.
url: https://yourdomain.com
  • Replace ‘yourdomain.com’ with a subdomain, or use the full domain.
- "traefik.http.routers.ghost-secure.rule=Host(`yourdomain.com`)"
  • Finally, replace ‘secretpassword’ with the password you set above on point two.
MYSQL_ROOT_PASSWORD: secretpassword

Creating and Starting The Services

Now everything is in place! Check your files if everything is in place and the variables are modified to your requirements.

Your file structure should be like this,

<Image of the file structure>

  • Now from this directory, run the command, you can change ‘site’ to anything you want.
docker stack deploy -c docker-compose.yml site

This takes a couple of a while to download the docker images and to get the SSL keys.

To list out the running services, run:

docker service ls

This lists the running services. If the REPLICAS are 0/1 wait for a few minutes, it might be preparing.

To check the status of individual services, run:

docker service ps <service name>

Replace <service name> with siteghost or sitetraefik or sitemysql.

To view the logs of individual services, run:

docker service logs -f <service name>

Hurray!! Now your site must be up and running. Visit the URLs you provided above for Traefik and Ghost.


Subscribe to my Weekly Newsletter and Follow for more DevOps, SRE, Linux, Python, Golang, Artificial Intelligence, Data Science, and Self-Hosting.


Additional Resources and References:

  • Setup SSH Keys:
How to Set Up SSH Keys on Ubuntu 20.04 | DigitalOcean
In this guide, we’ll focus on setting up SSH keys for an Ubuntu 20.04 installation. SSH keys provide an easy, secure way of logging into your server and are …
  • Add SSH Keys To DigitalOcean:
How to Upload SSH Public Keys to a DigitalOcean Account | DigitalOcean Documentation
Upload SSH public keys to your DigitalOcean account to make it easier to add keys to Droplets during creation.
  • Comparison between WordPress and Ghost:
Ghost: The simple, powerful WordPress alternative
Trying to find out how Ghost compares to WordPress? We’ve put together a full rundown of Ghost vs WordPress and the differences between them.
  • Traefik
Traefik Labs: Makes Networking Boring
Traefik is the world’s most popular cloud-native application networking stack, helping developers and devops build, deploy run microservices quickly and easily.
  • Docker
Docker overview
Docker explained in depth