L'auteur a choisi United Nations Foundation pour recevoir un don dans le cadre du programme Write for Donations.

La version WordPress originale de ce tutoriel a été rédigée par Kathleen Juell.

Introduction

Drupal est un système de gestion de contenu (CMS) écrit en PHP et distribué sous la licence publique générale GNU open-source. Drupal est utilisé à travers le monde par les particuliers et les organisations pour qui souhaitent propulser des sites gouvernementaux, des blogs personnels, des entreprises, etc. Ce qui rend Drupal unique par rapport aux autres frameworks CMS, c'est sa communauté croissante et son ensemble de fonctionnalités qui comprend notamment ses processus sécurisés, ses performances fiables, sa modularité et sa flexibilité d'adaptation.

Drupal nécessite l'installation de la pile LAMP (Linux, Apache, MySQL et PHP) ou LEMP (Linux, Nginx, MySQL et PHP). Cependant l'installation de chacun des composants est fastidieuse. Pour simplifier le processus d'installation de Drupal, nous pouvons utiliser des outils comme Docker et Docker Compose. Au cours de ce tutoriel, nous utiliserons des images Docker dans le cadre de l'installation des composants individuels dans les conteneurs Docker. En utilisant Docker Compose, nous pouvons définir et gérer plusieurs conteneurs de la base de données, l'application et la mise en réseau / communication entre eux.

Au cours de ce tutoriel, nous installerons Drupal à l'aide de Docker Compose afin de pouvoir profiter de la conteneurisation et déployer notre site Web Drupal sur des serveurs. Nous exécuterons les conteneurs d'une base de données MySQL, un serveur Web Nginx et Drupal. Nous sécuriserons également notre installation en obtenant des certificats TLS/SSL avec Let’s Encrypt pour le domaine que nous voulons associer à notre site. Enfin, nous configurerons un cron job pour renouveler nos certificats afin que notre domaine reste sécurisé.

Conditions préalables

Pour suivre ce tutoriel, nous aurons besoin de :

  • Un serveur de développement local fonctionnant sous Ubuntu 18.04, ainsi qu'un non-root user avec des privilèges sudo et un pare-feu actif. Pour savoir comment les configurer, veuillez consulter le présent Guide de configuration initiale du serveur.
  • Docker installé sur votre serveur, en suivant les Étapes 1 et 2 de Comment installer et utiliser Docker sur Ubuntu 18.04. Ce tutoriel a été testé sur la version 19.03.8.
  • Docker Compose installé sur votre serveur, en suivant l'Étape 1 de Comment installer Docker Compose sur Ubuntu 18.04. Ce tutoriel a été testé sur la version 1.21.2.
  • Un nom de domaine enregistré. Tout au long de ce tutoriel, nous utiliserons your_domain. Vous pouvez en obtenir un gratuitement sur Freenom ou utiliser le registre de domaine de votre choix.
  • Les deux enregistrements DNS suivants ont été configurés pour votre serveur. Vous pouvez suivre cette introduction au DNS DigitalOcean pour plus de détails sur la façon de les ajouter à un compte DigitalOcean, si c'est ce que vous utilisez :
    • Un enregistrement A avec your_domain pointant sur l'adresse IP publique de votre serveur.
    • Un enregistrement A avec www.your_domain​​​​​​ pointant sur l'adresse IP publique de votre serveur.

Étape 1 — Définition de la configuration du serveur Web

Avant d'exécuter des conteneurs, nous devons définir la configuration de notre serveur Web Nginx. Notre fichier de configuration comprendra des blocs de localisation spécifiques à Drupal, ainsi qu'un bloc de localisation qui permettra de diriger les demandes de vérification de Let’s Encrypt vers le client Certbot et de renouveler les certificats automatiquement.

Tout d'abord, créons un répertoire de projet pour la configuration de notre Drupal que nous appellerons drupal :

  • mkdir drupal

Allez dans le répertoire nouvellement créé :

  • cd drupal

Maintenant, nous pouvons créer un répertoire pour notre fichier de configuration :

  • mkdir nginx-conf

Ouvrez le fichier avec nano ou votre éditeur de texte favori :

  • nano nginx-conf/nginx.conf

Dans ce fichier, nous allons ajouter un bloc de serveur avec des directives pour le nom de notre serveur et la racine du document, ainsi que des blocs de localisation pour diriger la demande de certificats, le traitement PHP et les demandes d'actifs statiques du client Certbot.

Ajoutez le code suivant dans le fichier. Veillez à bien remplacer your_domain par votre nom de domaine :

~/drupal/nginx-conf/nginx.conf
server {
    listen 80;
    listen [::]:80;

    server_name your_domain www.your_domain;

    index index.php index.html index.htm;

    root /var/www/html;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/html;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass drupal:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }

    location = /favicon.ico {
        log_not_found off; access_log off;
    }
    location = /robots.txt {
        log_not_found off; access_log off; allow all;
    }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

Le bloc de serveur contient les informations suivantes :

Directives :

  • listen : indique à Nginx d'écouter le port 80, ce qui nous permettra d'utiliser le webroot plugin de Certbot pour nos demandes de certificat. Notez que nous n'incluons pas encore le port 443 - nous mettrons à jour notre configuration pour inclure SSL une fois que nous aurons réussi à obtenir nos certificats.

  • server_name : permet de définir notre nom de serveur et le bloc de serveur qui doit être utilisé pour les requêtes à notre serveur. Veillez à bien remplacer your_domain dans cette ligne avec votre propre nom de domaine.

  • index : permet de définir les fichiers qui serviront d'index lors du traitement des requêtes vers notre serveur. Ici, nous avons modifié l'ordre de priorité par défaut, en plaçant index.php devant index.html afin que Nginx priorise les fichiers appelés index.php lorsque cela est possible.

  • root : permet de nommer le répertoire racine des demandes à notre serveur. Ce répertoire, /var/www/html, est créé comme point de montage lorsque les instructions de notre Drupal Dockerfile procèdent à la construction. Ces instructions Dockerfile garantissent également à ce que les fichiers de la version Drupal soient bien remontés vers ce volume.

  • rewrite : si l'expression régulière spécifiée (^/core/authorize.php/core/authorize.php(.*)$) correspond à un URI de requête, l'URI est modifié comme spécifié dans la chaîne de remplacement (/core/authorize.php$1).

Blocs de localisation :

  • location ~ /.well-known/acme-challenge : ce bloc de localisation traitera les demandes du répertoire .well-known, dans lequel Certbot placera un fichier temporaire pour valider que le DNS de notre domaine se résout sur notre serveur. Une fois cette configuration en place, le webroot plugin de Certbot nous permettra d'obtenir des certificats pour notre domaine.

  • location/ : dans ce bloc de localisation, nous utiliserons une directive try_files pour rechercher les fichiers qui correspondent aux requêtes d'URI individuelles. Au lieu que l'état par défaut 404 Not Found ne nous soit renvoyé, nous passerons au contrôle du fichier index.php de Drupal avec les arguments de la requête.

  • location ~ \.php$ : ce bloc de localisation gérera le traitement PHP et enverra ces requêtes par procuration à notre conteneur drupal. Étant donné que notre image Drupal Docker sera basée sur l'image php:fpm, nous inclurons également des options de configuration spécifiques au protocole FastCGI dans ce bloc. Nginx nécessite un processeur PHP indépendant pour les requêtes PHP : dans notre cas, ces requêtes seront traitées par le processeur php-fpm inclus avec l'image php:fpm. En outre, ce bloc de localisation contient des directives, des variables et des options spécifiques à FastCGI qui, par procuration, renverront les requêtes vers l'application Drupal exécutée dans notre conteneur Drupal, configureront l'index favori de l'URI de requête analysée et analyseront les requêtes d'URI.

  • location ~ /\.ht : ce bloc traitera les fichiers .htaccess car Nginx ne les présentera pas. La directive deny_all veille à ce que les fichiers .htaccess ne soient jamais présentés aux utilisateurs.

  • location = /favicon.ico, location = /robots.txt : ces blocs veillent à que les requêtes adressées à /favicon.ico et /robots.txt ne soient pas enregistrées.

  • location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ : ce bloc désactive la journalisation des requêtes d'actifs statiques et veillent à ce que ces actifs soient strictement mis en cache, car leur présentation est généralement coûteuse.

Pour plus d'informations sur le proxy FastCGI, consultez Présentation et implémentation du proxy FastCGI dans Nginx. Pour plus d'informations sur le serveur et les blocs de localisation, consultez Comprendre le serveur Nginx et les algorithmes de sélection des blocs de localisation.

Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

Une fois Nginx configuré, vous pouvez commencer à créer des variables d'environnement afin de les transmettre à vos conteneurs d'application et de base de données au moment de l'exécution.

Étape 2 - Définition des variables d'environnement

Notre application Drupal nécessite une base de données (MySQL, PostgresQL, etc.) dans laquelle elle pourra sauvegarder les informations liées au site. Au moment de l'exécution, le conteneur Drupal devra avoir accès à certain nombre de variables d'environnement afin d'accéder au conteneur de la base de données (MySQL). Ces variables contiennent des informations sensibles comme les informations d'identification de la base de données. Nous ne pouvons donc pas les exposer directement dans le fichier Docker Compose, le fichier principal qui contient les informations sur la façon dont nos conteneurs s'exécuteront.

Comme toujours, il est vivement recommandé de configurer les valeurs sensibles dans le fichier .env et de restreindre sa circulation. Ainsi ces valeurs ne pourront être copiées dans nos référentiels de projet et être exposées publiquement.

Dans le répertoire principal du projet, ~/drupal, créez un fichier que vous nommerez .env, puis ouvrez-le :

  • nano .env

Ajoutez les variables suivantes au fichier .env et remplacez les sections en surbrillance par les données d'identification que vous souhaitez utiliser :

~/drupal/.env
MYSQL_ROOT_PASSWORD=root_password
MYSQL_DATABASE=drupal
MYSQL_USER=drupal_database_user
MYSQL_PASSWORD=drupal_database_password

Le mot de passe du compte administratif racine MySQL a maintenant été ajouté, ainsi que notre nom d'utilisateur et le mot de passe préférés pour notre base de données d'application.

Notre fichier .env contient des informations sensibles. Il est donc toujours recommandé de l'inclure dans les fichiers .gitignore et .dockerignore d'un projet afin qu'il ne soit pas ajouté à nos référentiels Git et à nos images Docker.

Si vous envisagez de travailler avec Git pour le contrôle de version, initialisez votre répertoire de travail actuel en tant que référentiel avec git init :

  • git init

Ouvrez le fichier .gitignore :

  • nano .gitignore

Ajoutez ce qui suit :

~/drupal/.gitignore
.env

Enregistrez et quittez le fichier.

De même, ouvrez le fichier .dockerignore :

  • nano .dockerignore

Ajoutez ensuite ce qui suit :

~/drupal/.dockerignore
.env
.git

Enregistrez et quittez le fichier.

Maintenant que nous avons pris des mesures pour protéger nos données d'identification en tant que variables d'environnement, passons à la prochaine étape de configuration de nos services dans un fichier docker-compose.yml.

Étape 3 — Définition des services avec Docker Compose

Docker Compose est un outil qui permet de définir et d'exécuter des applications Docker multi-conteneurs. Nous devons définir un fichier YAML pour configurer les services de notre application. Dans Docker Compose, un service est un conteneur en cours d'exécution et Compose nous permet de lier ces services avec des volumes et des réseaux partagés.

Nous allons créer différents conteneurs pour notre application, notre base de données et notre serveur Web Drupal. Parallèlement, nous allons également créer un conteneur pour exécuter Certbot et ainsi obtenir des certificats pour notre serveur web.

Créez un fichier docker-compose.yml :

  • nano docker-compose.yml

Ajoutez le code suivant afin de définir la version du fichier Compose et le service de base de données mysql :

~/drupal/docker-compose.yml
version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    env_file: .env
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

Parcourons ces étapes une par une ainsi que toutes les options de configuration du service mysql :

  • image : indique l'image qui sera utilisée / extraite pour créer le conteneur. Il est recommandé de toujours utiliser l'image avec la balise de version adaptée, à l'exclusion de la dernière balise pour éviter tout conflit à venir. Pour plus d'informations sur les meilleures pratiques pour Dockerfile, consultez la documentation de Docker.

  • container_name : permet de définir le nom du conteneur.

  • command : permet d'ignorer la commande par défaut (instruction CMD) qui se trouve dans l'image. MySQL a pris en charge différents plugins d'authentification, mais mysql_native_password est la méthode traditionnelle à utiliser pour procéder à l'authentification. Puisque PHP, et donc Drupal, ne prennent pas en charge la nouvelle authentification MySQL, nous devons définir --default-authentication-plugin=mysql_native_password qui servira de mécanisme d'authentification par défaut.

  • restart : permet de définir la politique de redémarrage du conteneur. La politique unless-stopped permet de redémarrer un conteneur, à moins qu'il ne soit arrêté manuellement.

  • env_file : permet d'ajouter les variables d'environnement à partir d'un fichier. Dans notre cas, les variables d'environnement seront lues à partir du fichier .env défini à l'étape précédente.

  • volumes : permet de faire remonter les chemins d'hôtes ou les volumes nommés, spécifiés comme sous-options vers un service. Nous allons faire remonter un volume nommé db-data dans le répertoire /var/lib/mysql sur le conteneur, où MySQL par défaut écrira ses fichiers de données.

  • networks : permet de définir le réseau interne auquel se joint notre service d'application. Nous allons définir les réseaux à la fin du fichier.

Maintenant que notre définition de service mysql a été établie, nous allons ajouter la définition du service d'application drupal à la fin du fichier :

~/drupal/docker-compose.yml
...
  drupal:
    image: drupal:8.7.8-fpm-alpine
    container_name: drupal
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - internal
      - external
    volumes:
      - drupal-data:/var/www/html

Dans cette définition de service, nous allons nommer notre conteneur et établir une politique de redémarrage, comme nous l'avons fait avec le service mysql. Nous allons également ajouter quelques options spécifiques à ce conteneur :

  • image : ici, nous utilisons l'image 8.7.8-fpm-alpine de Drupal. Cette image dispose du processeur php-fpm dont notre serveur web Nginx a besoin pour gérer le traitement PHP. De plus, nous utilisons l'image alpine, dérivée du projet Alpine Linux, qui réduira la taille de l'image dans son ensemble et qui est recommandée dans les meilleures pratiques Dockerfile. Drupal contient plusieurs versions d'images que vous devrez donc vérifier sur Dockerhub.

  • depends_on : permet d'exprimer la dépendance entre les services. En définissant le service mysql comme la dépendance de notre conteneur drupal, nous aurons la garantie que notre conteneur drupal sera créé après le conteneur mysql et permettra à notre application de démarrer en douceur.

  • networks : ici, nous avons ajouté ce conteneur au réseau externe ainsi que sur le réseau interne. Nous aurons ainsi la garantie que notre service mysql ne sera accessible qu'à partir du conteneur drupal via le réseau interne, tout en veillant à ce que ce conteneur reste accessible aux autres conteneurs via le réseau externe.

  • volumes : nous faisons remonter un volume nommé drupal-data au point de montage /var/www/html créé par l'image de Drupal. En utilisant un volume ainsi nommé, nous pourront partager notre code d'application avec d'autres conteneurs.

Ensuite, une fois le service drupal définit, ajoutons la définition du service Nginx :

~/drupal/docker-compose.yml
...
  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external

Encore une fois, nous allons nommer notre conteneur et le rendre dépendant du conteneur Drupal dans l'ordre de démarrage. Nous allons également utiliser une image alpine, l'image 1.17.4-alpine de Nginx.

Cette définition de service contient également les options suivantes :

  • ports : expose le port 80 pour permettre l'activation des options de configuration que nous avons définies dans notre fichier nginx.conf à l'étape 1.

  • volumes : ici, nous allons définir le volume et le chemin d'hôte nommés :

    • drupal-data:/var/www/html : permet de faire remonter notre code d'application Drupal dans le répertoire /var/www/html que nous allons configurer comme la racine dans notre bloc serveur Nginx.
    • ./nginx-conf:/etc/nginx/conf.d : permet de faire remonter le répertoire de configuration de Nginx sur l'hôte dans le répertoire pertinent du conteneur, en veillant à ce que toutes les modifications apportées aux fichiers de l'hôte soient reflétées dans le conteneur.
    • certbot-etc:/etc/letsencrypt : permet de faire remonter les certificats et les clés Let’s Encrypt de notre domaine dans le répertoire qui convient du conteneur.
    • networks : nous avons défini le réseau externe uniquement pour permettre la communication entre ce conteneur et le conteneur drupal et non pas avec le conteneur mysql.

Enfin, nous allons ajouter notre dernière définition de service pour le service certbot. Veillez à bien remplacer sammy@your_domain et your_domain par votre courriel et votre nom de domaine :

~/drupal/docker-compose.yml
...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain

Cette définition indique à Compose d'extraire l'image certbot/certbot de Docker Hub. Elle utilise également les volumes nommés pour partager les ressources avec le conteneur Nginx, y compris les certificats de domaine et la clé dans certbot-etc , ainsi que le code d'application dans drupal-data.

Nous avons également utilisé depend_on pour avoir la garantie que le conteneur certbot sera démarré après l'exécution du service webserver.

Nous n'avons spécifié aucun réseau ici car ce conteneur ne communiquera avec aucun service sur le réseau. Cela permet uniquement d'ajouter les certificats de domaine et la clé, que nous avons fait remonter à l'aide des volumes nommés.

Nous avons également inclus l'option command qui spécifie une sous-commande à exécuter avec la commande certbot par défaut du conteneur. Le client Certbot prend en charge des plugins afin de pouvoir obtenir et installer des certificats. Nous allons utiliser le plugin webroot pour obtenir un certificat en incluant certonly et --webroot sur la ligne de commande. Pour en savoir plus sur le plugin et les commandes supplémentaires, consultez la documentation officielle de Certbot.

Après avoir défini le service certbot, vous pouvez ajouter les définitions du réseau et du volume :

~/drupal/docker-compose.yml
...
networks:
  external:
    driver: bridge
  internal:
    driver: bridge

volumes:
  drupal-data:
  db-data:
  certbot-etc:

La clé des réseaux de niveau supérieur nous permet de spécifier les réseaux à créer. Se trouvant sur le même hôte de démon Docker, les réseaux permettent la communication entre les services / conteneurs sur tous les ports. Nous avons défini deux réseaux, interne et externe, pour sécuriser la communication des services webserver, drupal et mysql.

La clé volumes permet de définir les volumes drupal-data, db-data, et certbot-etc. Lorsque Docker crée des volumes, le contenu du volume est stocké dans un répertoire sur le système de fichiers hôte, /var/lib/docker/volumes/, qui est géré par Docker. On peut ensuite faire remonter le contenu de chaque volume à partir de ce répertoire dans tout conteneur qui utilise le volume en question. De cette façon, il est possible de partager le code et les données entre les conteneurs.

Le fichier docker-compose.yml terminé ressemblera à ceci :

~/drupal/docker-compose.yml
version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    env_file: .env
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

  drupal:
    image: drupal:8.7.8-fpm-alpine
    container_name: drupal
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - internal
      - external
    volumes:
      - drupal-data:/var/www/html

  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain

networks:
  external:
    driver: bridge
  internal:
    driver: bridge

volumes:
  drupal-data:
  db-data:
  certbot-etc:

Nous avons fini de définir nos services. Maintenant, nous pouvons procéder au démarrage du conteneur et tester nos requêtes de certificat.

Étape 4 - Obtention des certificats SSL et des données d'identification

Nous pouvons démarrer nos conteneurs avec la commande docker-compose up, qui créera et exécutera nos conteneurs dans l'ordre que nous avons spécifié. Si nos requêtes de domaine aboutissent, l'état de sortie dans notre résultat sera correct et les certificats adaptés seront remontés dans le dossier /etc/letsencrypt/live dans le conteneur du serveur Web.

Pour exécuter les conteneurs en arrière-plan, utilisez la commande docker-compose up avec l'indicateur -d :

  • docker-compose up -d

Vous obtiendrez un résultat similaire confirmant que vos services ont bien été créés :

Output
... Creating mysql ... done Creating drupal ... done Creating webserver ... done Creating certbot ... done

Vérifiez l'état des services en utilisant la commande docker-compose ps :

  • docker-compose ps

Nous verrons les services mysql, drupal et webserver apparaître avec un State​​​ ​de Up, tandis que certbot apparaîtra avec le message d'état 0 :

Output
Name Command State Ports -------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 drupal docker-php-entrypoint php-fpm Up 9000/tcp mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp

Si la colonne State des services mysql, drupal, ou Webserver indique un tout autre statut que Up ou si le conteneur cerbot indique un état de sortie autre que 0, veillez à bien vérifier les journaux de service avec la commande docker-compose logs :

  • docker-compose logs service_name

Nous pouvons maintenant vérifier si nos certificats ont bien été remontés sur le conteneur webserver à l'aide de la commande docker-compose exec :

  • docker-compose exec webserver ls -la /etc/letsencrypt/live

Cela donnera le résultat suivant :

Output
total 16 drwx------ 3 root root 4096 Oct 5 09:15 . drwxr-xr-x 9 root root 4096 Oct 5 09:15 .. -rw-r--r-- 1 root root 740 Oct 5 09:15 README drwxr-xr-x 2 root root 4096 Oct 5 09:15 your_domain

Maintenant que tout fonctionne correctement, nous pouvons modifier notre définition de service certbot pour supprimer l'indicateur --staging.

Ouvrez le fichier docker-compose.yml, accédez à la définition du service certbot et remplacez l'indicateur --staging dans l'option de commande par l'indicateur --force-renewal, qui indiquera à Certbot que vous souhaitez demander un nouveau certificat avec les mêmes domaines que ceux d'un certificat existant. La définition certbot mise à jour ressemblera à ceci :

~/drupal/docker-compose.yml
...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
...

Nous devons ré-exécuter docker-compose up pour recréer le conteneur certbot. Nous allons également inclure l'option --no-deps​​ pour indiquer à Compose qu'il peut démarrer le service webserver, puisqu'il est déjà en cours d'exécution :

  • docker-compose up --force-recreate --no-deps certbot

Nous verrons un résultat indiquant que notre requête de certificat est probante :

Output
Recreating certbot ... done Attaching to certbot certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | Plugins selected: Authenticator webroot, Installer None certbot | Renewing an existing certificate certbot | Performing the following challenges: certbot | http-01 challenge for your_domain certbot | http-01 challenge for www.your_domain certbot | Using the webroot path /var/www/html for all unmatched domains. certbot | Waiting for verification... certbot | Cleaning up challenges certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/your_domain/privkey.pem certbot | Your cert will expire on 2020-01-03. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0

Maintenant que nous avons réussi à générer nos certificats, nous pouvons mettre à jour notre configuration Nginx pour inclure SSL.

Étape 5 — Modification de la configuration du serveur Web et de la définition du service

Après avoir installé les certificats SSL dans Nginx, nous devrons rediriger toutes les requêtes HTTP vers HTTPS. Nous devrons également spécifier notre certificat SSL ainsi que les emplacements clés et ajouter des paramètres de sécurité et des en-têtes.

Puisque vous allez recréer le service webserver pour inclure ces ajouts, vous pouvez l'arrêter maintenant :

  • docker-compose stop webserver

Cela donnera le résultat suivant :

Output
Stopping webserver ... done

Ensuite, nous allons supprimer le fichier de configuration Nginx que nous avons créé précédemment :

  • rm nginx-conf/nginx.conf

Ouvrez une autre version du fichier :

  • nano nginx-conf/nginx.conf

Ajoutez le code suivant au fichier pour rediriger HTTP vers HTTPS et pour ajouter les identifiants, les protocoles et les en-têtes de sécurité SSL. N'oubliez pas de remplacer your_domain par votre domaine :

~/drupal/nginx-conf/nginx.conf
server {
    listen 80;
    listen [::]:80;

    server_name your_domain www.your_domain;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/html;
    }

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name your_domain www.your_domain;

    index index.php index.html index.htm;

    root /var/www/html;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass drupal:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }

    location = /favicon.ico {
        log_not_found off; access_log off;
    }
    location = /robots.txt {
        log_not_found off; access_log off; allow all;
    }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

Le bloc serveur HTTP spécifie le plugin webroot pour les demandes de renouvellement Certbot vers le répertoire .well-known/acme-challenge. Il comprend également une directive rewrite qui dirige les requêtes HTTP envoyées au répertoire racine vers HTTPS.

Le bloc serveur HTTPS active ssl et http2. Pour en savoir plus sur la façon dont HTTP/2 agit sur les protocoles HTTP et les avantages que cela peut avoir pour les performances du site Web, veuillez consulter l'introduction à Comment configurer Nginx avec la prise en charge HTTP/2 sur Ubuntu 18.04.

Ces blocs activent SSL, car nous avons inclus notre certificat SSL et nos emplacements clés ainsi que les en-têtes recommandés. Ces en-têtes nous permettront d'obtenir une note A sur les sites de test du serveur SSL Labs et Security Headers.

Nos directives root et index se trouvent également dans ce bloc, tout comme le reste des blocs de localisation spécifiques à Drupal abordés à l'étape 1.

Enregistrez et fermez le fichier de configuration Nginx mis à jour.

Avant de recréer le conteneur webserver, nous devrons ajouter un mappage de port 443 à notre définition de service webserver car nous avons activé les certificats SSL.

Ouvrez le fichier docker-compose.yml :

  • nano docker-compose.yml

Apportez les modifications suivantes dans la définition du service webserver :

~/drupal/docker-compose.yml
...
  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external
...

Une fois les certificats SSL activés, notre docker-compose.yml ressemblera à ceci :

~/drupal/docker-compose.yml
version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    env_file: .env
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

  drupal:
    image: drupal:8.7.8-fpm-alpine
    container_name: drupal
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - internal
      - external
    volumes:
      - drupal-data:/var/www/html

  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain

networks:
  external:
    driver: bridge
  internal:
    driver: bridge

volumes:
  drupal-data:
  db-data:
  certbot-etc:

Enregistrez et fermez le fichier. Recréons le service webserver avec notre configuration mise à jour :

  • docker-compose up -d --force-recreate --no-deps webserver

Cela donnera le résultat suivant :

Output
Recreating webserver ... done

Vérifiez les services avec docker-compose ps :

  • docker-compose ps

Nous verrons les services mysql, drupal et webserver avec l'état Up tandis que certbot sera fermé avec un message d'état 0 :

Output
Name Command State Ports -------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 drupal docker-php-entrypoint php-fpm Up 9000/tcp mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

Maintenant, tous nos services fonctionnent et nous sommes prêts à passer à l'installation de Drupal via l'interface Web.

Étape 6 — Finalisation de l'installation via l'interface Web

Terminons l'installation via l'interface Web de Drupal.

Dans un navigateur Web, accédez au domaine du serveur. N'oubliez pas de remplacer your_domain ici par votre nom de domaine :

https://your_domain

Sélectionnez la langue que vous souhaitez utiliser :

Sélectionnez la page des langues sur l'interface Web Drupal

Cliquez sur Save and continue. Nous atterrirons sur la page Installation profile. Drupal est composé de plusieurs profils, alors sélectionnez le profil Standard et cliquez sur Save and continue.

Sélectionnez la page de profil sur l'interface Web Drupal

Une fois le profil sélectionné, nous allons passer à la page Database configuration. Sélectionnez le type de base de données MySQL, MariaDB, Percona Server or equivalent. Ensuite, saisissez les valeurs Database name, username et password avec les valeurs correspondantes de MYSQL_DATABASE, MYSQL_USER et MYSQL_PASSWORD respectivement définies dans le fichier .env à l'étape 2. Cliquez sur Advanced Options et configurez la valeur Host sur le nom du conteneur de service mysql. Cliquez sur Save and continue.

Configuration de la page de base de données sur l'interface Web Drupal

Une fois la base de données configurée, l'installation des modules et des thèmes par défaut de Drupal commencera :

Installation de la page du site sur l'interface Web de Drupal

Une fois le site installé, nous atterrirons sur la page de configuration du site Drupal pour configurer le nom du site, l'e-mail, le nom d'utilisateur, le mot de passe et les paramètres régionaux. Complétez les informations et cliquez sur Save and continue :

Configuration de la page du site sur l'interface Web de Drupal

Après avoir cliqué sur Save and continue, nous pouvons voir la page Welcome to Drupal, qui montre que notre site Drupal est opérationnel.

La page Welcome to Drupal sur l'interface Web de Drupal

Maintenant que notre installation de Drupal est terminée, nous devons nous assurer que nos certificats SSL se renouvelleront automatiquement.

Étape 7 — Renouvellement des certificats

Les certificats Let’s Encrypt sont valables pendant 90 jours. Nous devons donc mettre en place un processus de renouvellement automatisé afin qu'ils ne puissent devenir caducs. Pour ce faire, vous pouvez créer une tâche avec l'utilitaire de planification cron. Dans ce cas, nous allons créer une tâche cron qui exécutera périodiquement un script qui permettra de renouveler nos certificats et de recharger notre configuration Nginx.

Créons le fichier ssl_renew.sh pour renouveler nos certificats :

  • nano ssl_renew.sh

Ajoutez le code suivant. N'oubliez pas de remplacer le nom du répertoire par votre propre non-root user :

~/drupal/ssl_renew.sh

#!/bin/bash

cd /home/sammy/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver

Ce script se transforme en répertoire de projet ~/drupal et exécute les commandes docker-compose suivantes.

  • docker-compose run: permet de démarrer un conteneur certbot et de supprimer la command fournie dans notre définition de service certbot. Au lieu d'utiliser la sous-commande certonly, nous utilisons ici la sous-commande renew, qui renouvellera les certificats qui sont sur le point d'expirer. Dans cet exemple, nous avons inclus l'option --dry-run pour tester notre script.

  • docker-compose kill : permet d'envoyer un signal SIGHUP au conteneur webserver pour recharger la configuration Nginx.

Fermez le fichier et rendez-le exécutable en exécutant la commande suivante :

  • sudo chmod +x ssl_renew.sh

Ensuite, ouvrez le fichier crontab root pour exécuter le script de renouvellement à un intervalle spécifié :

  • sudo crontab -e

Si vous éditez ce fichier pour la première fois, vous sevrez invité à choisir un éditeur de texte pour ouvrir le fichier :

Output
no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...

À la fin du fichier, ajoutez la ligne suivante, en remplaçant sammy par votre nom d'utilisateur :

crontab
...
*/5 * * * * /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1

L'intervalle de la tâche sera ainsi configurée à toutes les cinq minutes, afin que nous puissions tester si notre requête de renouvellement a bien fonctionné comme prévu. Nous avons également créé un fichier journal, cron.log, pour enregistrer les résultats pertinents de la tâche.

Après cinq minutes, utilisez la commande tail pour vérifier cron.log et voir si la demande de renouvellement s'est bien exécutée ou pas :

  • tail -f /var/log/cron.log

Vous verrez un résultat confirmant que qu'un renouvellement a bien été exécuté :

Output
** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Appuyez sur CTRL+C pour quitter le processus de tail.

Nous pouvons maintenant modifier le fichier crontab pour que le script soit exécuté tous les 2 jours de la semaine à 2 heures du matin. Remplacez la dernière ligne de la crontab par :

crontab
...
* 2 * * 2 /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1

Quittez et enregistrez le fichier.

Supprimons maintenant l'option --dry-run du script ssl_renew.sh. Tout d'abord, ouvrez-le :

  • nano ssl_renew.sh

Ensuite, remplacez le contenu par ce qui suit :

~/drupal/ssl_renew.sh
#!/bin/bash

cd /home/sammy/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver

Notre tâche cron se chargera désormais de l'expiration de nos certificats SSL en les renouvelant au moment voulu.

Conclusion

Dans ce didacticiel, nous avons utilisé Docker Compose pour créer une installation Drupal avec un serveur Web Nginx. Dans le cadre de ce processus, nous avons obtenu des certificats TLS SSL pour le domaine que nous voulions associer à notre site Drupal, et nous avons créé une tâche cron pour renouveler ces certificats au besoin.

Si vous souhaitez en savoir plus sur Docker, consultez notre page thématique consacrée à Docker.

0 Comments

Creative Commons License