*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

drupal illustration for: 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.
  • 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 the cloud provider pour plus de détails sur la façon de les ajouter à un compte the cloud provider, 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 &lt;^&gt;drupal&lt;^&gt;

				
			

Allez dans le répertoire nouvellement créé :

				
					
cd &lt;^&gt;drupal&lt;^&gt;

				
			

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

				
					
mkdir &lt;^&gt;nginx-conf&lt;^&gt;

				
			

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 :

				
					
[label ~/drupal/nginx-conf/nginx.conf]

server {

    listen 80;

    listen [::]:80;



    server_name &lt;^&gt;your_domain&lt;^&gt; www.&lt;^&gt;your_domain&lt;^&gt;;



    index &lt;^&gt;index.php&lt;^&gt; 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 &lt;^&gt;drupal&lt;^&gt;: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 :

				
					
[label ~/drupal/.env]

MYSQL_ROOT_PASSWORD=&lt;^&gt;root_password&lt;^&gt;

MYSQL_DATABASE=&lt;^&gt;drupal&lt;^&gt;

MYSQL_USER=&lt;^&gt;drupal_database_user&lt;^&gt;

MYSQL_PASSWORD=&lt;^&gt;drupal_database_password&lt;^&gt;

				
			

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 :

				
					
[label ~/drupal/.gitignore]

.env

				
			

Enregistrez et quittez le fichier.

De même, ouvrez le fichier .dockerignore :

				
					
nano .dockerignore

				
			

Ajoutez ensuite ce qui suit :

				
					
[label ~/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 :

				
					
[label ~/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 :

				
					
[label ~/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 :

				
					
[label ~/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 :

				
					
[label ~/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 &lt;^&gt;sammy@your_domain&lt;^&gt; --agree-tos --no-eff-email --staging -d &lt;^&gt;your_domain&lt;^&gt; -d www.&lt;^&gt;your_domain&lt;^&gt;

				
			

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 :

				
					
[label ~/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 :

				
					
[label ~/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 &lt;^&gt;sammy@your_domain&lt;^&gt; --agree-tos --no-eff-email --staging -d &lt;^&gt;your_domain&lt;^&gt; -d &lt;^&gt;www.your_domain&lt;^&gt;



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 :

				
					
[secondary_label 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 :

				
					
[secondary_label 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-&gt;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 &lt;^&gt;service_name&lt;^&gt;

				
			

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 :

				
					
[secondary_label 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 &lt;^&gt;your_domain&lt;^&gt;

				
			

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 :

				
					
[label ~/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 &lt;^&gt;sammy@your_domain&lt;^&gt; --agree-tos --no-eff-email &lt;^&gt;--force-renewal&lt;^&gt; -d &lt;^&gt;your_domain&lt;^&gt; -d www.&lt;^&gt;your_domain&lt;^&gt;

...

				
			

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 :

				
					
[secondary_label 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 &lt;^&gt;your_domain&lt;^&gt;

certbot      | http-01 challenge for &lt;^&gt;www.your_domain&lt;^&gt;

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/&lt;^&gt;your_domain&lt;^&gt;/fullchain.pem

certbot      |    Your key file has been saved at:

certbot      |    /etc/letsencrypt/live/&lt;^&gt;your_domain&lt;^&gt;/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 :

				
					
[secondary_label 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 :

				
					
[label ~/drupal/nginx-conf/nginx.conf]

server {

    listen 80;

    listen [::]:80;



    server_name &lt;^&gt;your_domain&lt;^&gt; www.&lt;^&gt;your_domain&lt;^&gt;;



    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 &lt;^&gt;your_domain&lt;^&gt; www.&lt;^&gt;your_domain&lt;^&gt;;



    index &lt;^&gt;index.php&lt;^&gt; index.html index.htm;



    root /var/www/html;



    server_tokens off;



    ssl_certificate /etc/letsencrypt/live/&lt;^&gt;your_domain&lt;^&gt;/fullchain.pem;

    ssl_certificate_key /etc/letsencrypt/live/&lt;^&gt;your_domain&lt;^&gt;/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 &lt;^&gt;drupal&lt;^&gt;: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 :

				
					
[label ~/drupal/docker-compose.yml]

...

  webserver:

    image: nginx:1.17.4-alpine

    container_name: webserver

    depends_on:

      - drupal

    restart: unless-stopped

    ports:

      - 80:80

      &lt;^&gt;- 443:443&lt;^&gt;

    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 :

				
					
[label ~/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 &lt;^&gt;sammy@your_domain&lt;^&gt; --agree-tos --no-eff-email --force-renewal -d &lt;^&gt;your_domain&lt;^&gt; -d &lt;^&gt;www.your_domain&lt;^&gt;



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 :

				
					
[secondary_label 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 :

				
					
[secondary_label 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-&gt;443/tcp, 0.0.0.0:80-&gt;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://&lt;^&gt;your_domain&lt;^&gt;

				
			

Sélectionnez la langue que vous souhaitez utiliser :

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.

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.

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

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 :

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.

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 :

				
					
[label ~/drupal/ssl_renew.sh]



#!/bin/bash



cd /home/&lt;^&gt;sammy&lt;^&gt;/drupal/

/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run &amp;&amp; \

/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 :

				
					
[secondary_label 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 :

				
					
[label crontab]

...

*/5 * * * * /home/&lt;^&gt;sammy&lt;^&gt;/drupal/ssl_renew.sh &gt;&gt; /var/log/cron.log 2&gt;&amp;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é :

				
					
[secondary_label 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/&lt;^&gt;your_domain&lt;^&gt;/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 :

				
					
[label crontab]

...

* 2 * * 2 /home/&lt;^&gt;sammy&lt;^&gt;/drupal/ssl_renew.sh &gt;&gt; /var/log/cron.log 2&gt;&amp;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 :

				
					
[label ~/drupal/ssl_renew.sh]

#!/bin/bash



cd /home/&lt;^&gt;sammy&lt;^&gt;/drupal/

/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew &amp;&amp; \

/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.