Du HTTPS en local avec Docker, Traefik, Traefik.me et Let’s Encrypt

Pour cet article, nous nous baseront sur la stack Docker décrite dans ce précédent article.

Introduction & objectifs

Aujourd’hui je vous propose une méthode (et il en existe pleins d’autre !) pour mettre en place très simplement, et sans trop d’efforts, un certificat SSL pour vos développements en local. Encore une fois l’objectif est d’être le plus proche d’un environnement de production, et donc le HTTPS est obligatoire ;-).

La méthode que j’utilise s’appuie sur plusieurs outils et services :

  • Docker et Docker-compose que l’on ne présente plus
  • Traefik, un excellent reverse proxy qui s’intègre très facilement dans un environnement Docker
  • Let’s Encrypt, qui nous fournira les certificats SSL
  • traefik.me, un service qui nous permet de disposer gratuitement d’un “domaine” pointant vers notre localhost (127.0.0.1)

Récupérer l’environnement de démonstration

Afin que vous puissiez facilement vous approprier la démarche, je vous propose de partir de l’environnement de développement Docker pour Symfony 5 que nous avions mis en place précédemment. Nous renommons le nom du repertoire pour qu’il soit plus court !

git clone https://gitlab.com/yoandev.co/environnement-de-developpement-symfony-5-avec-docker-et-docker-compose.git
mv environnement-de-developpement-symfony-5-avec-docker-et-docker-compose/ docker_https

Puis on entre dans le répertoire et on ouvre le contenu du répertoire dans son IDE favoris (J’utilise Visual Studio Code).

cd docker_https
code .

On démarre l’environnement Docker.

docker-compose up -d

On vérifie que l’environnement fonctionne en ouvrant la page http://127.0.0.1:8741. Si vous voyez “Not Found” c’est bon signe !

Histoire d’avoir un peu mieux que “Not Found”, nous créons l’arborescence de répertoires attendue par la stack docker que nous avons récupérée au début du tuto, puis nous y créons une basique page “Hello World”.

mkdir project
mkdir project/public
cd project/public
touch index.php

(Nous donnons le nom index.php, car c’est ce qui est attendu par la configuration du conteneur Apache).

Voici un exemple de page “Hello World” tout ce qu’il y à de plus basique.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>Hello World</h1>
  <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum dicta reiciendis earum beatae voluptates voluptatem quisquam placeat illum sint, dolores quos officia pariatur, doloremque quis ex similique dolorum dolorem exercitationem.</p>
</body>
</html>

Mise en place de Traefik

Maintenant que nous avons en environnement Docker fonctionnel en HTTP, passons aux choses sérieuses (sans se prendre au sérieux si vous le voulez bien 😉 ).

La première étape consiste à ajouter un conteneur Traefik à notre docker-compose.yml. Et pour cela, nous n’allons pas ré-inventer la poudre, nous allons nous baser sur la configuration décrite dans la documentation de Traefik.me et en particulier sur l’exemple de docker-compose.yml (ça tombe bien n’est-ce pas !?).

Première étape, ajouter un service traefik à notre docker-compose.yml.

 traefik:
        restart: unless-stopped
        image: traefik:v2.0.2
        ports:
          - "80:80"
          - "443:443"
        labels:
          - "traefik.http.services.traefik.loadbalancer.server.port=8080"
        volumes:
          - ./traefik.yml:/etc/traefik/traefik.yml
          - ./tls.yml:/etc/traefik/tls.yml
          - /var/run/docker.sock:/var/run/docker.sock
          - certs:/etc/ssl/traefik
        networks:
            - dev

Vous aurez peut-être noté que dans les volumes nous faisons appels à deux fichiers (que nous allons mettre en place juste en dessous) et un volume “certs” à déclarer en fin du fichier docker-compose.yml.

volumes:
    db-data:
    certs:

Nous récupérons les deux fichiers traefik.yml et tls.yml dans le lien avec le docker-compose.yml fournit dans la doc de traefik.me.

wget https://gist.githubusercontent.com/pyrou/4f555cd55677331c742742ee6007a73a/raw/570ea39c2c53da783d8c078452ba050349b89456/tls.yml
wget https://gist.githubusercontent.com/pyrou/4f555cd55677331c742742ee6007a73a/raw/570ea39c2c53da783d8c078452ba050349b89456/traefik.yml

Vous devriez trouver désormais à la racine de votre répertoire deux nouveaux fichiers. Étudions-les rapidement, pour comprendre le rôle de chacun.

#traefik.yml

logLevel: INFO

api:
  insecure: true
  dashboard: true

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  file:
    filename: /etc/traefik/tls.yml
  docker:
    endpoint: unix:///var/run/docker.sock
    watch: true
    exposedByDefault: true
    defaultRule: "HostRegexp(`{{ index .Labels \"com.docker.compose.service\"}}.traefik.me`,`{{ index .Labels \"com.docker.compose.service\"}}-{dashed-ip:.*}.traefik.me`)"

Le fichier traefik.yml est le fichier de paramétrage de Traefik. Il permet en autre de définir les points d’entrée de traefik, ici le port 80 ou le port 443. C’est également dans ce fichier que l’on précise le “provider” pour les certificats TLS. Dans cette configuration il est sous forme de fichiers.

#tls.yml

tls:
  stores:
    default:
      defaultCertificate:
        certFile: /etc/ssl/traefik/cert.pem
        keyFile: /etc/ssl/traefik/privkey.pem
  certificates:
    - certFile: /etc/ssl/traefik/cert.pem
      keyFile: /etc/ssl/traefik/privkey.pem

Le fichier tls.yml est le fichier qui précise à traefik ou il peut trouver les fichiers de certificat. Nous allons voir juste plus loin comment nous les récupérons.

Récupération des certificats Let’s Encrypt de traefik.me

Comme nous allons utiliser la solution de traefik.me, nous devons télécharger leur certificat wildcard (fournit par Let’s Encrypt) et le mettre à disposition de notre conteneur traefik (dans le fichier tls.yml).

Capture d’écran du site https://traefik.me/

Encore une fois, nous allons suivre l’exemple donné dans le docker-compose.yml fournit par traefik.me. Concrètement la solution proposée est simple et astucieuse ! Elle consiste à la mise en place d’un conteneur qui à pour unique mission de télécharger les fichiers du certificat de traefik.me (clé publique et clé privée).

  reverse-proxy-https-helper:
    image: alpine
    command: sh -c "cd /etc/ssl/traefik
      && wget traefik.me/cert.pem -O cert.pem
      && wget traefik.me/privkey.pem -O privkey.pem"
    volumes:
      - certs:/etc/ssl/traefik

Mettre notre conteneur Apache derrière traefik

On touche au but, dernière ligne droite ! Il ne nous nous reste plus qu’a “brancher” notre conteneur Apache (www) derrière le reverse-proxy traefik, et à activer le HTTPS.

Traefik, dans un environnement Docker, est vraiment agréable à utiliser, car désormais nous ne toucherons plus à la configuration de traefik, mais ajouterons des “labels” aux conteneurs que l’on souhaite “brancher” à traefik.

Sans surprise, nous utilisons la configuration proposer par traefik.me. Nous ajoutons donc 3 labels à notre conteneur “www” et nous pouvons supprimer le mappage de port qui devient inutile.

    www:
        build: php
        container_name: www_docker_symfony
        volumes:
            - ./php/vhosts:/etc/apache2/sites-enabled
            - ./:/var/www
        restart: always
        labels:
            - "traefik.http.routers.app1.rule=Host(`app1.traefik.me`)"
            - "traefik.http.routers.app1-tls.tls.domains[0].main=app1.traefik.me"
            - "traefik.http.routers.app1-tls.tls.domains[0].sans=app1-*.traefik.me"
        networks:
            - dev

Pour la démonstration, nous utiliserons le sous domaine app1.traefik.me pour exposer notre application.

Nous pouvons relancer les conteneurs.

docker-compose up -d

Nous pouvons vérifier que la configuration de traefik fonctionne bien en ouvrant la page (encore en http à cette étape) http://app1.traefik.me.

Activer le HTTPS

Pour activer le HTTPS, rien de bien compliquer, nous devons ajouter un quatrième “labels” à notre conteneur Apache (www). Ce label permet d’activer l’utilisation des certificats, je vous invite à jeter un coup d’œil à la documentation pour approfondir le sujet.

    www:
        build: php
        container_name: www_docker_symfony
        volumes:
            - ./php/vhosts:/etc/apache2/sites-enabled
            - ./:/var/www
        restart: always
        labels:
            - "traefik.http.routers.app1.rule=Host(`app1.traefik.me`)"
            - "traefik.http.routers.app1-tls.tls.domains[0].main=app1.traefik.me"
            - "traefik.http.routers.app1-tls.tls.domains[0].sans=app1-*.traefik.me"
            - "traefik.http.routers.app1.tls=true"
        networks:
            - dev

On redémarre les conteneurs.

docker-compose up -d

Et on vérifie que tout est OK à l’adresse https://app1.traefik.me ! Félicitation !

Conclusions et dépôt GitLab

Encore une fois je reste stupéfait de la praticité de Docker pour mettre en œuvre des solutions rapidement et efficacement. Nous n’avons ici qu’effleuré la puissance de Traefik et je vous invite fortement à étudier la documentation si vous souhaitez aller plus loin.

Vous disposez désormais d’un environnement de développement complet, avec du HTTPS, cool non ?

Vous trouverez les sources des fichiers sur ce dépôt GitLab.

Laisser un commentaire

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

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.