Table of Contents
*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
sudoet 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 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 <^>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 :
[label ~/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 port80, ce qui nous permettra d'utiliser le webroot plugin de Certbot pour nos demandes de certificat. Notez que nous n'incluons pas encore le port443– 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çantindex.phpdevantindex.htmlafin que Nginx priorise les fichiers appelésindex.phplorsque 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 directivetry_filespour rechercher les fichiers qui correspondent aux requêtes d'URI individuelles. Au lieu que l'état par défaut404 Not Foundne nous soit renvoyé, nous passerons au contrôle du fichierindex.phpde 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'imagephp: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 processeurphp-fpminclus avec l'imagephp: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.htaccesscar Nginx ne les présentera pas. La directivedeny_allveille à ce que les fichiers.htaccessne soient jamais présentés aux utilisateurs.
location = /favicon.ico, location = /robots.txt: ces blocs veillent à que les requêtes adressées à/favicon.icoet/robots.txtne 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=<^>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 :
[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 ladernièrebalise 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, maismysql_native_passwordest 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_passwordqui servira de mécanisme d'authentification par défaut.
restart: permet de définir la politique de redémarrage du conteneur. La politiqueunless-stoppedpermet 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.envdé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-datadans le répertoire/var/lib/mysqlsur le conteneur, où MySQL par défaut écrira ses fichiers de données.
networks: permet de définir le réseauinterneauquel 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'image8.7.8-fpm-alpinede Drupal. Cette image dispose du processeurphp-fpmdont notre serveur web Nginx a besoin pour gérer le traitement PHP. De plus, nous utilisons l'imagealpine, 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 servicemysqlcomme la dépendance de notre conteneurdrupal, nous aurons la garantie que notre conteneurdrupalsera créé après le conteneurmysqlet permettra à notre application de démarrer en douceur.
networks: ici, nous avons ajouté ce conteneur au réseauexterneainsi que sur le réseauinterne. Nous aurons ainsi la garantie que notre servicemysqlne sera accessible qu'à partir du conteneurdrupalvia le réseauinterne, tout en veillant à ce que ce conteneur reste accessible aux autres conteneurs via le réseauexterne.
volumes: nous faisons remonter un volume nommédrupal-dataau point de montage/var/www/htmlcréé 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 port80pour permettre l'activation des options de configuration que nous avons définies dans notre fichiernginx.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/htmlque 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éseauexterneuniquement pour permettre la communication entre ce conteneur et le conteneurdrupalet non pas avec le conteneurmysql.
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 <^>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 :
[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 <^>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 :
[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->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 :
[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 <^>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 :
[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 <^>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 :
[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 <^>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 :
[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 <^>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 :
[label ~/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 :
[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 <^>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 :
[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->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 :
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/<^>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 conteneurcertbotet de supprimer lacommandfournie dans notre définition de servicecertbot. Au lieu d'utiliser la sous-commandecertonly, nous utilisons ici la sous-commanderenew, qui renouvellera les certificats qui sont sur le point d'expirer. Dans cet exemple, nous avons inclus l'option--dry-runpour tester notre script.
docker-compose kill: permet d'envoyer un signalSIGHUPau conteneurwebserverpour 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/<^>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é :
[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/<^>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 :
[label 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 :
[label ~/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.