Tut's LinuxDocker

[docker-compose] Ghost 3 et Traefik v2

Le but de cette documentation est de vous fournir un fichier .yml clé en main pour installer le CMS Ghost derrière Traefik.


Article mis à jour suite aux commentaires de ldez oncernant un soucis de configuration côté Traefik (mélange entre conf’ statique et dynamique) (merci !!)

Mise à jour : 28/09/2020

  • refonte des fichiers .yml de traefik (suppression des .toml)
  • refonte du fichier docker-compose.yml
  • utilisation des variables d’environnement (fichier .env)

Ghost est un CMS pour propulser des sites web type « blog », un peu comme ComputerZ Solutions ;). Cet outil nécessite une base de données dans laquelle y seront stockées toutes les données (pages, posts et configurations). J’utilise Traefik en frontal de Ghost – plus de détails à cette adresse (CZS).

Quelques pré-requis avant de se lancer : avoir Docker (pour Ubuntu ou CentOS 7) et docker-compose installé sur votre machine. J’utilise le chemin « /srv/docker » sur mon serveur et y ait créé un dossier « conf » où sont stockés les fichiers de configuration pour les différents services, un dossier « traefikdynamic » pour les configurations personnalisés pour Traefik et enfin un dossier « logs » pour Traefik.

De plus, il est important de créer le fichier acme.json dans le dossier « conf » avec les droits nécessaires avant de créer les conteneurs :

touch /srv/docker/conf/acme.json
chmod 0600 /srv/docker/conf/acme.json

Sans plus attendre, voici le fichier docker-compose.yml :

---
version: '3.6'
services:
  traefik:
    container_name: traefik
    image: traefik:picodon
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
      - 8080:8080 # used to have the traefik dashboard # used to have the traefik dashboard
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./conf/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./conf/traefikdynamic:/traefikdynamic:ro
      - ./logs/traefik.log:/etc/traefik/applog.log
      - ./conf/acme.json:/acme.json

  sqlghost:
    container_name: sqlghost
    image: mariadb:bionic
    restart: unless-stopped
    volumes:
      - datasqlghost:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: '1'
      MYSQL_USER: ${MYSQLUSER}
      MYSQL_PASSWORD: ${MYSQLPASSWORD}
      MYSQL_DATABASE: ${MYSQLDB}

  ghost:
    container_name: cmsghost
    image: ghost:3
    restart: unless-stopped
    volumes:
      - dataghost:/var/lib/ghost/content
      - ./conf/config.production.json:/var/lib/ghost/config.production.json:ro
    depends_on:
      - sqlghost
    labels:
      traefik.enable: true
      traefik.http.routers.ghost-https.entrypoints: websecure
      traefik.http.routers.ghost-https.rule: Host(`ghost.czs.local`)
      traefik.http.routers.ghost-https.middlewares: compression@file, security@file
      traefik.http.routers.ghost-https.tls: true
      traefik.http.routers.ghost-https.tls.certresolver: "letsencrypt"

volumes:
  datasqlghost:
  dataghost:

Les lignes sont explicites : création du service « traefik » pour le conteneur reverse-proxy, le service « sqlghost » à base de MariaDB et le service « webghost » pour le CMS Ghost. Seul Ghost a des labels correspondant pour Traefik – avec ces quelques lignes, votre Ghost sera « routable » vers le web et automatiquement géré en SSL.
Vous remarquerez aussi des volumes complémentaires comme « /etc/timezone » et « /etc/localtime » – utilisé pour être en relation avec le serveur hôte (qui est à l’heure via NTP) et donc avoir un horodatage cohérent. Les fichiers de configurations sont à côté du docker-compose.yml, libre à vous de les placer ailleurs (et de modifier le chemin dans la conf)

Les labels Traefik mis en place dans ce fichier docker-compose.yml sont dit en « configuration statique ». Avant de lancer les conteneurs, vous devez encore créer des fichiers, notamment deux pour Traefik :

fichier « traefik.yml »

global:
  sendAnonymousUsage: false
  checkNewVersion: false

api:
  #insecure: true
  dashboard: true
  #debug: true

log:
  filePath: "/etc/traefik/applog.log"
  level: INFO

providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: false
    watch: true
    swarmMode: false

  file:
    directory: /traefikdynamic
    watch: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: contact@czs.local
#      caServer: https://acme-staging-v02.api.letsencrypt.org/directory
      caServer: https://acme-v02.api.letsencrypt.org/directory
      storage: acme.json
      keyType: EC256
      httpChallenge:
        entryPoint: web

Le fichier de configuration Traefik se décompose sous forme de blocs – tout est assez explicite, je ne vais pas faire une description pour chaque ligne.

Le second fichier traefik_dynamic.yml est à placer dans un dossier « traefikdynamic », dans le dossier « conf » précédement initialisé.

tls:
  options:
    default:
      minVersion: VersionTLS12
      sniStrict: true
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_AES_128_GCM_SHA256
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
      curvePreferences:
        - CurveP521
        - CurveP384

http:
  middlewares:
    compression:
      compress:
        excludedContentTypes:
          - text/event-stream

    security:
      headers:
        accessControlAllowMethods:
          - GET
          - OPTIONS
          - PUT
        #accessControlAllowOriginList = "*"
        accessControlMaxAge: 100
        addVaryHeader: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        frameDeny: true
        sslRedirect: true
        sslForceHost: true
        stsPreload: true
        #ContentSecurityPolicy = "default-src 'self' 'unsafe-inline'"
        customFrameOptionsValue: SAMEORIGIN
        referrerPolicy: same-origin
        featurePolicy: vibrate 'self'
        stsSeconds: 315360000

    authentification:
      basicAuth:
        users: # admon / totolasticot
        - admon:$2y$10$4IgUsvlCwENsF18B9t7AoegQ7eWZVfWxPFRhNfBWz7F00h1X2oZFe

Ghost a aussi besoin d’un fichier de configuration pour être exploitable. Suivez bien le formalisme du fichier .json requis – ci-dessous un exemple de conf’ :

{
    "url": "https://ghost.czs.local",
    "server": {
      "port": 2368,
      "host": "0.0.0.0"
    },
    "database": {
      "client": "mysql",
      "connection": {
        "host": "sqlghost",
        "user": "ghost",
        "port": "3306",
        "password": "sqlghostuserpassword",
        "database": "ghost"
      }
    },
    "privacy": {
      "useUpdateCheck": false,
      "useGravatar": false,
      "useRpcPing": false,
      "useStructuredData": true
    },
    "process": "systemd",
    "paths": {
      "contentPath": "/var/lib/ghost/content"
    }
}

config.production.json

Enfin, créer à la racine du dossier (à côté du fichier docker-compose.yml) un fichier intitulé .env, qui contiendra les variables quant aux identifiants SQL et les versions des applications.

MYSQLUSER=ghost
MYSQLPASSWORD=sqlghostuserpassword
MYSQLDB=ghost

Maintenant que vos fichiers sont créés, vous pouvez initier un « docker-compose up -d » et voir la magie s’opérer… 🙂 Le site web sous Ghost sera accessible au nom de domaine stipulé dans la conf’, Traefik effectuera automatiquement le lien/la redirection et le tout avec du HTTPS via Let’s Encrypt.

Vous pouvez trouver l’ensemble des scripts à cette adresse Github.

Bercé par l'informatique depuis mon plus jeune âge, je transforme ma passion en expertise.

Leave a reply

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

You may also like