J'utilise sur mon serveur dédié, un blog qui utilise le CMS "ghost". Lui même nécessite une base de données MySQL et forcément pour mettre en ligne le tout, j'utilise Traefik.
Nous allons voir un cas pratique de déploiement d'un blog avec ces 3 technologies. Au programme :

  • Création du fichier docker-compose pour créer ma stack,
  • Publier ma stack avec Traefik.

Pré-requis

Forcément l'installation de Docker sur mon serveur dédié, et également docker-compose.

Vous pouvez également sécuriser votre serveur avec quelques règles IPTABLES.

Mais comme vous suivez ce blog régulièrement, vous êtes prêts ! Moi aussi ...

Création de notre stack

Afin de réaliser une telle installation, le premier élément à vérifier est tout simplement la documentation du service que l'on souhaite publier.

Dans notre cas : Ghost. Un rapide tour sur la documentation de l'image docker présente sur le hub vous permettra de récupérer un fichier de stack :

# by default, the Ghost image will use SQLite (and thus requires no separate database container)
# we have used MySQL here merely for demonstration purposes (especially environment-variable-based configuration)

version: '3.1'

services:

  ghost:
    image: ghost:1-alpine
    restart: always
    ports:
      - 8080:2368
    environment:
      # see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example

Ce fichier est un bon point de départ. Je vais apporter quelques modifications à ce fichier afin de réaliser les opérations suivantes :

  • Ajouter notre routeur edge : Traefik
  • Retirer le NAT 8080 vers 2368
  • Créer les labels nécessaires à Traefik pour publier notre blog

Traefik

Ajoutons donc la déclaration de Traefik au précédent fichier. J'en profite pour passer le fichier en version 3.7 ( il s'agit de la version de docker-compose. Dans ce cas présent, cela ne change pas grand chose mais autant utiliser la dernière syntaxe en date ... ) :

version: '3.7'
services:
    reverse-proxy:
        image: traefik:2.1
        restart: always
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - ./traefik.yml:/etc/traefik/traefik.yml:ro

Je vais laisser pour cet article le dashboard accessible à tous ( le port 8080 ). ⚠️ Si vous souhaitez mettre cette stack sur une IP publique, retirez le ou pensez à restreindre l'accès par IP à cette ressource ou par authentification ! ⚠️

J'utilise dans cette stack un fichier YAML que nous avons déjà vu :

api:
  insecure: true

providers:
  docker:
    exposedByDefault: false

entryPoints:
    http:
      address: :80

Configuration de Ghost

À ce stade vous pouvez déjà déployer Traefik afin de vous assurer qu'aucune erreur ne soit présente :

docker-compose up -d reverse-proxy

Ajoutons maintenant les labels nécessaires à Ghost :

version: '3.7'
services:
    reverse-proxy:
        image: traefik:2.1
        restart: always
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - ./traefik.yml:/etc/traefik/traefik.yml:ro

    ghost:
        image: ghost:3
        restart: always
        environment:
            database__client: mysql
            database__connection__host: db
            database__connection__user: root
            database__connection__password: example
            database__connection__database: ghost
            url: http://ghost.docker.localhost/
        labels:
            - "traefik.enable=true"
            - "traefik.http.services.monblog.loadbalancer.server.port=2368"
            - "traefik.http.routers.monblog.rule=Host(`ghost.docker.localhost`)"
            - "traefik.http.routers.monblog.entrypoints=http"

    db:
        image: mysql:5.7
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: example

Pensez à ajouter ghost.docker.localhost à votre fichier hosts et vous pouvez lancer votre stack :

docker-compose up -d

À ce stade, tout fonctionne. Mais il faut être honnête pour une éventuelle mise en production, il manque quelques éléments !

5, 4, 3, 2, 1 ... 🚀

Pour la mise en production, voici quelques éléments qu'il nous faut modifier ou ajouter :

  • Des volumes pour les données persistentes.
  • Créer des réseaux pour nos containeurs.
  • Et bien sûr ... Changer les mots de passes :)

Modifions notre fichier docker-compose afin d'ajouter tout ça !

Quelles données devons-nous rendre persistantes ? La documentation de Ghost nous donne l'information : /var/lib/ghost/content. Mais il faut également penser à un volume pour les données MySQL.

Enfin afin de faire communiquer Traefik et Ghost, je vais mettre en place un réseau entre ces deux containeurs. Et un second réseau pour Ghost et MySQL afin de limiter leur communication dans ce réseau.

Dernier détail, je donne un nom fixe à mes containeurs pour faciliter l'accès au log par exemple :

version: '3.7'
services:
    reverse-proxy:
        image: traefik:2.1
        restart: always
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - ./traefik.yml:/etc/traefik/traefik.yml:ro
        networks:
            - traefik
        container_name: traefik

    ghost:
        image: ghost:3
        restart: always
        environment:
            database__client: mysql
            database__connection__host: db
            database__connection__user: ghost
            database__connection__password: motdepasseutilisateurghost
            database__connection__database: ghost
            url: http://ghost.docker.localhost/
        labels:
            - "traefik.enable=true"
            - "traefik.docker.network=traefik"
            - "traefik.http.services.monblog.loadbalancer.server.port=2368"
            - "traefik.http.routers.monblog.rule=Host(`ghost.docker.localhost`)"
            - "traefik.http.routers.monblog.entrypoints=http"
        volumes:
            - www-data:/var/lib/ghost/content
        networks:
            - traefik
            - lan
        container_name: ghost

    db:
        image: mysql:5.7
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: motdepasseutilisateurroot
            MYSQL_USER: ghost
            MYSQL_DATABASE: ghost
            MYSQL_PASSWORD: motdepasseutilisateurghost
        volumes:
            - mysql-data:/var/lib/mysql
        networks: 
            - lan
        container_name: mysql

volumes:
  mysql-data:
    name: mysql-data

  www-data:
    name: www-data

networks:
  lan:
    name: lan

  traefik:
    name: traefik

Un petit up de votre stack et rendez-vous sur : http://ghost.docker.localhost !


Dans un prochain article, nous verrons comment ajouter le HTTPS à notre blog avec un certificat obtenant A ou A+ sur https://www.ssllabs.com. Ainsi que quelques règles de filtrage : Comme par exemple, limiter l'accès au répertoire /ghost par IP. On ajoutera également quelques headers de securité afin d'obtenir un bon score sur https://securityheaders.com/.

Liens utiles :

  • https://github.com/lfache/deployer-ghost-avec-traefik : Voici les fichiers de configurations sur Github !