Installation de Docker et de Traefik sur un NAS ASUSTOR

La problématique est la suivante. Je souhaite un reverse proxy permettant d’accéder de l’extérieur (internet) à toutes les applications internes, sans ouvrir de ports. La solution c’est le reverse proxy. Asus Data Master (ADM pour les intimes) a bien un outil appelé reverse proxy qui permet d’accéder en https à une application ou un service tournant en interne de façon non sécurisée (http), mais pour ceci il faut ouvrir un port « externe » qui sera associé au port interne de l’application visée, donc on revient quelque part au point de départ.

En fouillant un peu, j’ai trouvé l’outil qu’il me fallait : Traefik. Cet outil est nativement un reverse-proxy. Il permet d’associer…

Cependant, pour l’installer de façon la plus pratique, il s’avère qu’il est préférable de passer par Docker. Docker est une sorte d’outil permettant de virtualiser des applications spécifiques, de façon qu’elles tournent sur leur propre système et ne dépendent pas du système sur lequel elles doivent tourner. Il se trouve que c’est extrêmement pratique pour installer sur des systèmes « propriétaires » comme ce qui fait tourner un NAS (e.g. ADM pour Asustor, pour Synology ou pour QNap). On utilise pour ça des distributions ultra-légères de GNU/Linux qui sont donc des systèmes indépendants.

Installation de Docker

Pour installer Docker sur ADM, rien de plus simple puisque l’application est supportée par AppCentral (le système de gestion des applications de ADM). Dans la foulée, j’ai également installé Portainer CE (Community Edition) qui est une interface graphique permettant de gérer l’installation et la gestion de docker divers, simple à prendre en main, surtout pour quelqu’un qui ne connai(ssai)t pas Docker (comme moi).

Installation de Traefik

Après avoir tenté d’aller au plus simple en installer Traefik directement de Portainer, je me suis finalement convaincu de mettre un peu la main à la pâte et l’installer manuellement. Dans mon installation, les répertoires Docker installés par ADM sont situés dans /volume1/ Docker. J’ai créé un répertoire « Traefik » dans celui-ci et créé les fichiers suivants.

Avant de se lancer dans ce qui suit, il est important de créer en avance de phase les domaines. Personnellement j’ai acheté pour trois francs six sous un nom de domaine chez OVH : www.webdot.fr. Puis j’ai créé tous les sous-domaines que j’utilise en CNAME. Si le sous-domaine n’existe pas lancer traefik au terme de tout ce qui suit gérèrera une erreur.

Voici le fichier docker-compose.yml : j’ai mis quelques commentaires dans le texte

restart: always # politique de redémarrage
image: traefik:latest # c'est l'image qui est téléchargée et sur laquelle va se baser votre propre installation
container_name: Traefik # le nom du docker tel qu'il apparaîtra dans votre installation
ports: # les ports redirigés dans le docker
- "443:443"
- "80:80"
network_mode: bridge # le nom du "réseau" propre aux images docker qui tournent

environment: # tout ce bloc est destiné à gérer les certificats de Let's Encrypt des différents sous-domaines en une seule passe. 

- "TZ=Europe/Paris"
- "OVH_ENDPOINT=ovh-eu"
- "OVH_APPLICATION_KEY=xxxxxxxxxxxxxxxxxxx"
- "OVH_APPLICATION_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "OVH_CONSUMER_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx"

volumes: # les volumes montés permettent de conserver les modifications que les fichiers de configuration ou dans des répertoires. On peut faire un lien (bind) ou monter un vrai répertoire du système hôte sur le répertoire interne du docker. 

- /volume1/Docker/Traefik/traefik.log:/traefik.log
- /volume1/Docker/Traefik/traefik.toml:/etc/traefik/traefik.toml
- /volume1/Docker/Traefik/services.toml:/etc/traefik/services.toml
- /volume1/Docker/Traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock

labels:

- "traefik.enable=true"

# http to https redirection
- "traefik.protocols=https"
- "traefik.http.middlewares.https_redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.https_redirect.redirectscheme.permanent=true"
- "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"  
- "traefik.http.routers.redirs.entrypoints=http"  
- "traefik.http.routers.redirs.middlewares=https_redirect"  

# Traefik dashboard ==> c'est le bloc qui permet d'accéder à l'interface traefik pour voir son fonctionnement et déterminer les bugs éventuels
- "traefik.http.routers.api.rule=Host(`traefik.webdot.fr`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.entrypoints=https,http"
- "traefik.http.routers.api.middlewares=https_redirect"
- "traefik.http.routers.api.tls=true"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
#- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$Wkc.0oXU$$wd24kJ89JhbcGoMruIynk1"

# Docker interface ==> pour accéder à l'interface de Portainer
- "traefik.http.routers.docker.entrypoints=https,http"
- "traefik.http.routers.docker.middlewares=https_redirect"
- "traefik.http.routers.docker.rule=Host(`docker.webdot.fr`)"
- "traefik.http.routers.docker.service=docker@file"
- "traefik.http.routers.docker.tls=true"
- "traefik.http.routers.docker.tls.certresolver=letsencrypt"

# Apache2 reverse proxy ==> Permet de remplacer le serveur Apache du NAS, j'y reviendrai
- "traefik.http.routers.www.entrypoints=https,http"
- "traefik.http.routers.www.middlewares=https_redirect"
- "traefik.http.routers.www.rule=Host(`www.webdot.fr`)"
- "traefik.http.routers.www.service=www@file"
- "traefik.http.routers.www.tls=true"
- "traefik.http.routers.www.tls.certresolver=letsencrypt"

# Nextcloud service ==> pour l'accès à Nextcloud
- "traefik.http.routers.cloud.rule=Host(`cloud.webdot.fr`)" # ligne 1
- "traefik.http.routers.cloud.entrypoints=https" # ligne 2
- "traefik.http.routers.cloud.middlewares=https_redirect" # ligne 3
- "traefik.http.routers.cloud.service=cloud@file" # ligne 4
- "traefik.http.routers.cloud.tls=true" # ligne 5
- "traefik.http.routers.cloud.tls.certresolver=letsencrypt" # ligne 6

.......... Et vous pouvez mettre plein d'autres blocs sur le schéma du bloc pour Nextcloud ci-dessous.

Prenons l’exemple d’un bloc : Nextcloud. Le bloc permet de déterminer le sous-domaine qui permettra d’accéder au service (ligne #1), de spécifier qu’on souhaite passer par un accès sécurisé (lignes #2 et #3). Pour ceci on définit un « service » qui relie au fichier service.toml dont je parle ci-dessous et qui relie le sous-domaine à l’accès non sécurisé du service ou de l’application (ligne #4). Les deux dernières lignes (lignes #5 et #6) s’occupent de la gestion des certificats Let’s Encrypt en passant par un « resolver » défini dans le fichier traefik.toml ci-dessous. Il faut noter que Traefik gère automatiquement la regénération des certificats avant qu’ils ne soient caduques (tous les trois mois).

services.toml : dans ce fichier on fait le lien entre un bloc sous-domaine du fichier docker-compose.yml et l’accès non sécurisé en interne de l’application ou du service : par exemple, on associe le service « cloud » à l’url http://192.168.1.140:32680. Le sous-domaine qui permet d’y accéder est défini dans le bloc correspondant (cloud) dans le fichier docker-compose.yml.

[http]
  [http.services]
    [http.services.docker]
      [http.services.docker.loadBalancer]
        [[http.services.docker.loadBalancer.servers]]
          url = "http://192.168.1.140:19900"
    [http.services.cloud]
      [http.services.cloud.loadBalancer]
        [[http.services.cloud.loadBalancer.servers]]
          url = "http://192.168.1.140:32680"

.......... Et à chaque bloc du fichier docker-compose.yml il faut associer un bloc de 4 lignes comme pour le service "cloud"

Enfin, il faut un troisième fichier qui permet de spécifier ports, fichiers, gestionnaire de certificats et niveau de log le cas échéant. C’est le fichier traefik.toml.

[entryPoints.https]
  address = ":443"

[serversTransport]
  insecureSkipVerify = true

[api]
   
[providers.docker]
  endpoint = "unix:///var/run/docker.sock"
          
[providers.file]
  filename = "/etc/traefik/services.toml"

[certificatesResolvers.letsencrypt.acme]
  email = "eric.devito@webdot.fr"
  storage = "/acme.json"
#  caserver = "https://acme-staging-v02.api.letsencrypt.org/directory"
  [certificatesResolvers.letsencrypt.acme.httpChallenge]
    entryPoint = "http"
#  [certificatesResolvers.letsencrypt.acme.dnsChallenge]
#    provider: ovh
#    delayBeforeCheck: 0

[log]
  filePath = "/traefik.log"
  level = "ERROR" # on peut fixer le niveau de log à DEBUG, PANIC, FATAL, ERROR, WARN ou INFO

Attention : la ligne

#  caserver = "https://acme-staging-v02.api.letsencrypt.org/directory"

est très importante. Il est indispensable de décommenter cette ligne pour faire des tests. Une fois décommentée, la génération des certificats Let’s Encrypt se fait sur un serveur de test qui n’a pas de limitation (ou alors très élevée), si elle n’est pas décommentée, on attaque directement le serveur de Let’s Encrypt et s’il y a des soucis dans la configuration, on peut consommer TRES vite la quantité de certificats autorisée en une semaine (aujourd’hui, cinquante). Une fois qu’on est certain de la configuration, on peut commenter cette ligne, relancer Traefik, et les certificats sont générés et enregistrés dans un fichier acme.json, dans la racine du répertoire /volume1/Docker/Traefik, cf. la ligne :

- /volume1/Docker/Traefik/acme.json:/acme.json

dans le fichier docker-compose.yml.

Les lignes commentées

#  [certificatesResolvers.letsencrypt.acme.dnsChallenge]
#    provider: ovh
#    delayBeforeCheck: 0

Sont relatives à la gestion des certificats Let’s Encrypt via les SANS, mais je ne suis pas encore arrivé à utiliser ces particularités. J’ai quand même conservé ces lignes, quand j’aurai le temps de régler ça.

Avant tout essai, il faut bien créer le fichier acme.json, et lui attribuer les droits d’accès « 600 »:

root@astorus:/volume1/Docker/Traefik# touch acme.json && chmod 600 acme.json

Normalement, une fois que tout est bien configuré, on peut lancer le docker Traefik avec la commande :

root@astorus:/volume1/Docker/Traefik# docker-compose up -d

Le docker se lance, va alimenter le fichier de certificats acme.json, on peut suivre les erreurs éventuelles dans le fichier traefik.log. Les sous-domaines doivent bien entendu être actifs comme expliqué ci-dessus.

Maintenant, on aimerait accéder aux certificats d’une façon différente que de la façon dont ils sont présentés dans le fichier acme.json. Pour ceci j’ai trouvé un outil très utile : traefik-certs-dumper. Cet outil permet d’extraire les certificats d’un fichier .json. Avec la commande :

root@astorus:/volume1/Docker/Traefik#./traefik-certs-dumper file --version v2 --clean --crt-name cert --key-name private --source ./acme.json --dest ./dump/

On extrait tous les certificats pour les ré-écrire dans le répertoire ./dump. Attention, l’option –version v2 est indispensable, sinon ça ne marchera pas.

Du coup, j’ai créé un petit script qui me permet de récupérer les certificats et de les ranger là où je veux 🙂 . Cela m’est utile essentiellement pour gérer les certificats pour le serveur de mail (dans mon cas : mail.webdot.fr). Je les recopie (voir les lignes cp…) dans des répertoires persistants de postfix et dovecot dont je parlerai dans un prochain post.

J’ai mis ce script dans crontab et je le fais tourner une fois par mois, et je suis certain d’avoir dans ce répertoire dump les certificats en cours (vu que les certificats Let’s Encrypt sont générés tous les trois mois).

#!/bin/sh

cd /volume1/Docker/Traefik

# Extract the certificates from the acme.json file
./traefik-certs-dumper file --version v2 --clean --crt-name cert --key-name private --source ./acme.json --dest ./dump/

# Copy mail hostname certificates to Postfix docker volume ssl directory and apply r/w rights
cp ./dump/certs/mail.webdot.fr.crt /usr/local/AppCentral/docker-ce/docker_lib/volumes/postfix_conf/_data/ssl/
cp ./dump/private/mail.webdot.fr.key  /usr/local/AppCentral/docker-ce/docker_lib/volumes/postfix_conf/_data/ssl/
chmod 644 /usr/local/AppCentral/docker-ce/docker_lib/volumes/postfix_conf/_data/ssl/*.crt
chmod 600 /usr/local/AppCentral/docker-ce/docker_lib/volumes/postfix_conf/_data/ssl/*.key

# Copy mail hostname certificates to Dovecot docker volume ssl directory and apply r/w rights
cp ./dump/certs/mail.webdot.fr.crt /usr/local/AppCentral/docker-ce/docker_lib/volumes/a73949915e9e61ca225db3388b315f490be498483ac0e9f87ed621a37768d18b/_data/ssl/cert.pem
cp ./dump/private/mail.webdot.fr.key  /usr/local/AppCentral/docker-ce/docker_lib/volumes/a73949915e9e61ca225db3388b315f490be498483ac0e9f87ed621a37768d18b/_data/ssl/key.pem
chmod 644 /usr/local/AppCentral/docker-ce/docker_lib/volumes/a73949915e9e61ca225db3388b315f490be498483ac0e9f87ed621a37768d18b/_data/ssl/cert.pem
chmod 600 /usr/local/AppCentral/docker-ce/docker_lib/volumes/a73949915e9e61ca225db3388b315f490be498483ac0e9f87ed621a37768d18b/_data/ssl/key.pem

Et voilà, normalement, les sous-domaines ont maintenant accès à tout les services correspondants (sous réserve que ces derniers soient installés avant !).

Laisser un commentaire

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