Comment installer WordPress avec Docker Compose

De Get Docs
Aller à :navigation, rechercher

Introduction

WordPress est un Système de gestion de contenu (CMS) gratuit et open source construit sur une base de données MySQL avec traitement PHP. Grâce à son architecture de plug-in extensible et à son système de modèles, et au fait que la majeure partie de son administration peut être effectuée via l'interface Web, WordPress est un choix populaire lors de la création de différents types de sites Web, des blogs aux pages de produits en passant par les sites de commerce électronique.

L'exécution de WordPress implique généralement l'installation d'une pile LAMP (Linux, Apache, MySQL et PHP) ou LEMP (Linux, Nginx, MySQL et PHP), ce qui peut prendre du temps. Cependant, en utilisant des outils comme Docker et Docker Compose, vous pouvez simplifier le processus de configuration de votre pile préférée et d'installation de WordPress. Au lieu d'installer manuellement des composants individuels, vous pouvez utiliser des images, qui normalisent des éléments tels que les bibliothèques, les fichiers de configuration et les variables d'environnement, et exécuter ces images dans des conteneurs, des processus isolés qui s'exécutent sur un système d'exploitation partagé. De plus, en utilisant Compose, vous pouvez coordonner plusieurs conteneurs — par exemple, une application et une base de données — pour communiquer entre eux.

Dans ce didacticiel, vous allez créer une installation WordPress multi-conteneurs. Vos conteneurs comprendront une base de données MySQL, un serveur Web Nginx et WordPress lui-même. Vous sécuriserez également votre installation en obtenant des certificats TLS/SSL avec Let's Encrypt pour le domaine que vous souhaitez associer à votre site. Enfin, vous mettrez en place une tâche cron pour renouveler vos certificats afin que votre domaine reste sécurisé.

Conditions préalables

Pour suivre ce tutoriel, vous aurez besoin de :

  • Un serveur exécutant Ubuntu 18.04, avec un utilisateur non root avec des privilèges sudo et un pare-feu actif. Pour savoir comment les configurer, veuillez consulter ce 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.
  • Docker Compose installé sur votre serveur, en suivant l'étape 1 de Comment installer Docker Compose sur Ubuntu 18.04.
  • Un nom de domaine enregistré. Ce tutoriel utilisera example.com tout au long. Vous pouvez en obtenir un gratuitement sur Freenom, ou utiliser le bureau d'enregistrement de domaine de votre choix.
  • Les deux enregistrements DNS suivants sont configurés pour votre serveur. Vous pouvez suivre cette introduction à DigitalOcean DNS 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 example.com pointant vers l'adresse IP publique de votre serveur.
    • Un enregistrement A avec www.example.com pointant vers l'adresse IP publique de votre serveur.

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

Avant d'exécuter des conteneurs, notre première étape consistera à définir la configuration de notre serveur Web Nginx. Notre fichier de configuration comprendra des blocs d'emplacement spécifiques à WordPress, ainsi qu'un bloc d'emplacement pour diriger les demandes de vérification Let's Encrypt vers le client Certbot pour les renouvellements de certificats automatisés.

Tout d'abord, créez un répertoire de projet pour votre configuration WordPress appelé wordpress et accédez-y :

mkdir wordpress && cd wordpress

Ensuite, créez un répertoire pour le fichier de configuration :

mkdir nginx-conf

Ouvrez le fichier avec nano ou votre éditeur préféré :

nano nginx-conf/nginx.conf

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

Collez le code suivant dans le fichier. Assurez-vous de remplacer example.com par votre propre nom de domaine :

~/wordpress/nginx-conf/nginx.conf

server {
        listen 80;
        listen [::]:80;

        server_name example.com www.example.com;

        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;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress: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;
        }
}

Notre bloc serveur comprend les informations suivantes :

Directives :

  • listen : Cela indique à Nginx d'écouter sur le port 80, ce qui nous permettra d'utiliser le plugin webroot 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 obtenu nos certificats avec succès.
  • server_name : Cela définit le nom de votre serveur et le bloc de serveur qui doit être utilisé pour les requêtes vers votre serveur. Assurez-vous de remplacer example.com dans cette ligne par votre propre nom de domaine.
  • index : La directive index définit les fichiers qui seront utilisés comme index lors du traitement des requêtes vers votre serveur. Nous avons modifié l'ordre de priorité par défaut ici, en déplaçant index.php devant index.html afin que Nginx donne la priorité aux fichiers appelés index.php lorsque cela est possible.
  • root : Notre directive root nomme le répertoire racine pour les requêtes vers notre serveur. Ce répertoire, /var/www/html, est créé en tant que point de montage au moment de la construction selon les instructions de notre WordPress Dockerfile. Ces instructions Dockerfile garantissent également que les fichiers de la version WordPress sont montés sur ce volume.

Blocs d'emplacement :

  • location ~ /.well-known/acme-challenge : ce bloc d'emplacement traitera les requêtes vers le répertoire .well-known, où Certbot placera un fichier temporaire pour valider que le DNS de notre domaine se résout sur notre serveur. Avec cette configuration en place, nous pourrons utiliser le plugin webroot de Certbot pour obtenir des certificats pour notre domaine.
  • location / : dans ce bloc d'emplacement, nous utiliserons une directive try_files pour vérifier les fichiers qui correspondent aux requêtes URI individuelles. Au lieu de renvoyer un statut 404 Not Found par défaut, nous allons toutefois passer le contrôle au fichier index.php de WordPress avec les arguments de la requête.
  • location ~ \.php$ : ce bloc de localisation gérera le traitement PHP et transmettra ces requêtes à notre conteneur wordpress. Étant donné que notre image WordPress 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. De plus, ce bloc d'emplacement comprend des directives, des variables et des options spécifiques à FastCGI qui transmettront les requêtes proxy à l'application WordPress exécutée dans notre conteneur wordpress, définiront l'index préféré pour l'URI de requête analysée et analyseront les requêtes URI.
  • location ~ /\.ht : ce bloc gérera les fichiers .htaccess puisque Nginx ne les servira pas. La directive deny_all garantit que les fichiers .htaccess ne seront jamais servis aux utilisateurs.
  • location = /favicon.ico, location = /robots.txt : ces blocs garantissent que les demandes adressées à /favicon.ico et /robots.txt ne seront pas enregistrées.
  • location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ : ce bloc désactive la journalisation des demandes d'actifs statiques et garantit que ces actifs peuvent être mis en cache, car ils sont généralement coûteux à servir.

Pour plus d'informations sur le proxy FastCGI, voir Comprendre et mettre en œuvre le proxy FastCGI dans Nginx. Pour plus d'informations sur les blocs de serveur et d'emplacement, voir Comprendre les algorithmes de sélection de serveur et de bloc d'emplacement Nginx.

Enregistrez et fermez le fichier lorsque vous avez terminé l'édition. Si vous avez utilisé nano, faites-le en appuyant sur CTRL+X, Y, puis ENTER.

Une fois votre configuration Nginx en place, vous pouvez passer à la création de variables d'environnement à transmettre à vos conteneurs d'application et de base de données lors de l'exécution.

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

Votre base de données et vos conteneurs d'application WordPress auront besoin d'accéder à certaines variables d'environnement lors de l'exécution pour que les données de votre application persistent et soient accessibles à votre application. Ces variables incluent à la fois des informations sensibles et non sensibles : des valeurs sensibles pour votre mot de passe MySQL root et l'utilisateur et le mot de passe de la base de données d'application, et des informations non sensibles pour le nom et l'hôte de votre base de données d'application.

Plutôt que de définir toutes ces valeurs dans notre fichier Docker Compose - le fichier principal qui contient des informations sur le fonctionnement de nos conteneurs - nous pouvons définir les valeurs sensibles dans un fichier .env et restreindre sa circulation. Cela empêchera ces valeurs d'être copiées dans nos référentiels de projet et d'être exposées publiquement.

Dans votre répertoire de projet principal, ~/wordpress, ouvrez un fichier nommé .env :

nano .env

Les valeurs confidentielles que nous allons définir dans ce fichier incluent un mot de passe pour notre utilisateur MySQL root, ainsi qu'un nom d'utilisateur et un mot de passe que WordPress utilisera pour accéder à la base de données.

Ajoutez les noms et valeurs de variables suivants au fichier. N'oubliez pas de fournir vos propres valeurs ici pour chaque variable :

~/wordpress/.env

MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password

Nous avons inclus un mot de passe pour le compte administratif root, ainsi que notre nom d'utilisateur et mot de passe préférés pour notre base de données d'applications.

Enregistrez et fermez le fichier lorsque vous avez terminé l'édition.

Étant donné que votre fichier .env contient des informations sensibles, vous devez vous assurer qu'il est inclus dans les fichiers .gitignore et .dockerignore de votre projet, qui indiquent Git et Docker quels fichiers pas copier dans vos référentiels Git et images Docker, respectivement.

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 ensuite un fichier .gitignore :

nano .gitignore

Ajoutez .env au fichier :

~/wordpress/.gitignore

.env

Enregistrez et fermez le fichier lorsque vous avez terminé l'édition.

De même, c'est une bonne précaution d'ajouter .env à un fichier .dockerignore, afin qu'il ne se retrouve pas sur vos conteneurs lorsque vous utilisez ce répertoire comme contexte de construction.

Ouvrez le fichier :

nano .dockerignore

Ajoutez .env au fichier :

~/wordpress/.dockerignore

.env

En dessous, vous pouvez éventuellement ajouter des fichiers et répertoires associés au développement de votre application :

~/wordpress/.dockerignore

.env
.git
docker-compose.yml
.dockerignore

Enregistrez et fermez le fichier lorsque vous avez terminé.

Une fois vos informations sensibles en place, vous pouvez maintenant passer à la définition de vos services dans un fichier docker-compose.yml.

Étape 3 - Définir les services avec Docker Compose

Votre fichier docker-compose.yml contiendra les définitions de service pour votre configuration. Un service dans Compose est un conteneur en cours d'exécution, et les définitions de service spécifient des informations sur la façon dont chaque conteneur s'exécutera.

À l'aide de Compose, vous pouvez définir différents services afin d'exécuter des applications multi-conteneurs, car Compose vous permet de lier ces services avec des réseaux et des volumes partagés. Cela sera utile pour notre configuration actuelle puisque nous allons créer différents conteneurs pour notre base de données, notre application WordPress et notre serveur Web. Nous allons également créer un conteneur pour exécuter le client Certbot afin d'obtenir des certificats pour notre serveur Web.

Pour commencer, ouvrez le fichier docker-compose.yml :

nano docker-compose.yml

Ajoutez le code suivant pour définir la version de votre fichier Compose et le service de base de données db :

~/wordpress/docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes: 
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

La définition de service db contient les options suivantes :

  • image : Cela indique à Compose quelle image extraire pour créer le conteneur. Nous épinglons ici l'image mysql:8.0 pour éviter de futurs conflits car l'image mysql:latest continue d'être mise à jour. Pour plus d'informations sur l'épinglage de version et la prévention des conflits de dépendance, consultez la documentation Docker sur Dockerfile best practices.
  • container_name : Ceci spécifie un nom pour le conteneur.
  • restart : définit la stratégie de redémarrage du conteneur. La valeur par défaut est no, mais nous avons configuré le conteneur pour qu'il redémarre à moins qu'il ne soit arrêté manuellement.
  • env_file : cette option indique à Compose que nous souhaitons ajouter des variables d'environnement à partir d'un fichier appelé .env, situé dans notre contexte de construction. Dans ce cas, le contexte de construction est notre répertoire actuel.
  • environment : cette option vous permet d'ajouter des variables d'environnement supplémentaires, en plus de celles définies dans votre fichier .env. Nous allons définir la variable MYSQL_DATABASE égale à wordpress pour donner un nom à notre base de données d'application. Comme il s'agit d'informations non sensibles, nous pouvons les inclure directement dans le fichier docker-compose.yml.
  • volumes : ici, nous montons un volume appelé dbdata dans le répertoire /var/lib/mysql du conteneur. Il s'agit du répertoire de données standard pour MySQL sur la plupart des distributions.
  • command : cette option spécifie une commande pour remplacer l'instruction CMD par défaut pour l'image. Dans notre cas, nous ajouterons une option à la commande standard mysqld de l'image Docker, qui démarre le serveur MySQL sur le conteneur. Cette option, --default-authentication-plugin=mysql_native_password, définit la variable système --default-authentication-plugin sur mysql_native_password, en spécifiant quel mécanisme d'authentification doit régir les nouvelles demandes d'authentification au serveur. Étant donné que PHP et donc notre image WordPress ne prendront pas en charge la nouvelle authentification par défaut de MySQL , nous devons effectuer cet ajustement afin d'authentifier l'utilisateur de notre base de données d'application.
  • networks : Ceci précise que notre service applicatif rejoindra le réseau app-network, que nous définirons en bas du fichier.

Ensuite, sous votre définition de service db, ajoutez la définition de votre service d'application wordpress :

~/wordpress/docker-compose.yml

...
  wordpress:
    depends_on: 
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

Dans cette définition de service, nous nommons notre conteneur et définissons une politique de redémarrage, comme nous l'avons fait avec le service db. Nous ajoutons également quelques options spécifiques à ce conteneur :

  • depends_on : cette option garantit que nos conteneurs démarreront dans l'ordre de dépendance, le conteneur wordpress commençant après le conteneur db. Notre application WordPress repose sur l'existence de notre base de données d'application et de l'utilisateur, donc exprimer cet ordre de dépendance permettra à notre application de démarrer correctement.
  • image : pour cette configuration, nous utilisons l'image WordPress 5.1.1-fpm-alpine. Comme indiqué dans Étape 1, l'utilisation de cette image garantit que notre application disposera du processeur php-fpm dont Nginx a besoin pour gérer le traitement PHP. Il s'agit également d'une image alpine, dérivée du projet Alpine Linux, qui nous aidera à réduire la taille globale de notre image. Pour plus d'informations sur les avantages et les inconvénients de l'utilisation d'images alpine et si cela a du sens pour votre application, consultez la discussion complète dans la section Image Variants du Docker Hub Page d'images WordPress .
  • env_file : Encore une fois, nous spécifions que nous voulons extraire des valeurs de notre fichier .env, car c'est là que nous avons défini l'utilisateur et le mot de passe de notre base de données d'application.
  • environment : Ici, nous utilisons les valeurs que nous avons définies dans notre fichier .env, mais nous les attribuons aux noms de variables attendus par l'image WordPress : WORDPRESS_DB_USER et WORDPRESS_DB_PASSWORD. Nous définissons également un WORDPRESS_DB_HOST, qui sera le serveur MySQL exécuté sur le conteneur db accessible sur le port par défaut de MySQL, 3306. Notre WORDPRESS_DB_NAME aura la même valeur que celle que nous avons spécifiée dans la définition du service MySQL pour notre MYSQL_DATABASE : wordpress.
  • volumes : nous montons un volume nommé appelé wordpress sur le point de montage /var/www/html créé par l'image WordPress. L'utilisation d'un volume nommé de cette manière nous permettra de partager notre code d'application avec d'autres conteneurs.
  • networks : nous ajoutons également le conteneur wordpress au réseau app-network.

Ensuite, sous la définition du service d'application wordpress, ajoutez la définition suivante pour votre service Nginx webserver :

~/wordpress/docker-compose.yml

...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

Encore une fois, nous nommons notre conteneur et le rendons dépendant du conteneur wordpress dans l'ordre de démarrage. Nous utilisons également une image alpine — l'image 1.15.12-alpine Nginx.

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

  • ports : Cela expose le port 80 pour activer les options de configuration que nous avons définies dans notre fichier nginx.conf dans Étape 1.
  • volumes : Ici, nous définissons une combinaison de volumes nommés et lier les montures : wordpress:/var/www/html : cela montera notre code d'application WordPress dans le répertoire /var/www/html, le répertoire que nous avons défini comme racine dans notre bloc de serveur Nginx. ./nginx-conf:/etc/nginx/conf.d : Cela liera le montage du répertoire de configuration Nginx sur l'hôte au répertoire approprié sur le conteneur, garantissant que toutes les modifications que nous apportons aux fichiers sur l'hôte seront reflétées dans le récipient. certbot-etc:/etc/letsencrypt : Cela montera les certificats et les clés Let's Encrypt pertinents pour notre domaine dans le répertoire approprié sur le conteneur.

Et encore une fois, nous avons ajouté ce conteneur au réseau app-network.

Enfin, sous votre définition webserver, ajoutez votre dernière définition de service pour le service certbot. Assurez-vous de remplacer l'adresse e-mail et les noms de domaine répertoriés ici par vos propres informations :

~/wordpress/docker-compose.yml

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com

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

Encore une fois, nous avons utilisé depends_on pour spécifier que le conteneur certbot doit être démarré une fois que le service webserver est en cours d'exécution.

Nous avons également inclus une option command qui spécifie une sous-commande à exécuter avec la commande par défaut certbot du conteneur. La sous-commande certonly obtiendra un certificat avec les options suivantes :

  • --webroot : Cela indique à Certbot d'utiliser le plug-in Webroot pour placer les fichiers dans le dossier Webroot pour l'authentification. Ce plugin dépend de la méthode de validation HTTP-01, qui utilise une requête HTTP pour prouver que Certbot peut accéder aux ressources d'un serveur qui répond à un nom de domaine donné.
  • --webroot-path : Ceci spécifie le chemin du répertoire webroot.
  • --email : votre e-mail préféré pour l'enregistrement et la récupération.
  • --agree-tos : ceci indique que vous acceptez le contrat d'abonnement de ACME.
  • --no-eff-email : Cela indique à Certbot que vous ne souhaitez pas partager votre e-mail avec Electronic Frontier Foundation (EFF). N'hésitez pas à l'omettre si vous préférez.
  • --staging : cela indique à Certbot que vous souhaitez utiliser l'environnement intermédiaire de Let's Encrypt pour obtenir des certificats de test. L'utilisation de cette option vous permet de tester vos options de configuration et d'éviter d'éventuelles limites de demande de domaine. Pour plus d'informations sur ces limites, veuillez consulter la documentation sur les limites de débit de Let's Encrypt.
  • -d : Cela vous permet de spécifier les noms de domaine que vous souhaitez appliquer à votre demande. Dans ce cas, nous avons inclus example.com et www.example.com. Assurez-vous de les remplacer par votre propre domaine.

Sous la définition de service certbot, ajoutez vos définitions de réseau et de volume :

~/wordpress/docker-compose.yml

...
volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  

Notre clé de niveau supérieur volumes définit les volumes certbot-etc, wordpress et dbdata. 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. Le contenu de chaque volume est ensuite monté à partir de ce répertoire vers n'importe quel conteneur utilisant le volume. De cette manière, il est possible de partager du code et des données entre conteneurs.

Le réseau de pont défini par l'utilisateur app-network permet la communication entre nos conteneurs puisqu'ils se trouvent sur le même hôte de démon Docker. Cela rationalise le trafic et la communication au sein de l'application, car il ouvre tous les ports entre les conteneurs sur le même réseau de ponts sans exposer aucun port au monde extérieur. Ainsi, nos conteneurs db, wordpress et webserver peuvent communiquer entre eux, et nous n'avons qu'à exposer le port 80 pour un accès frontal à L'application.

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

~/wordpress/docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes: 
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress:
    depends_on: 
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com

volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  

Enregistrez et fermez le fichier lorsque vous avez terminé l'édition.

Une fois vos définitions de service en place, vous êtes prêt à démarrer les conteneurs et à tester vos demandes de certificat.

Étape 4 - Obtention de certificats SSL et d'informations 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 demandes de domaine aboutissent, nous verrons le statut de sortie correct dans notre sortie et les bons certificats montés dans le dossier /etc/letsencrypt/live sur le conteneur webserver.

Créez les conteneurs avec docker-compose up et le drapeau -d, qui exécutera les conteneurs db, wordpress et webserver en arrière-plan:

docker-compose up -d

Vous verrez une sortie confirmant que vos services ont été créés :

OutputCreating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot   ... done

À l'aide de docker-compose ps, vérifiez l'état de vos services :

docker-compose ps

Si tout a réussi, vos services db, wordpress et webserver seront Up et le conteneur certbot aura quitté avec un Message d'état 0 :

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

Si vous voyez autre chose que Up dans la colonne State pour les services db, wordpress ou webserver, ou un état de sortie autre que 0 pour le conteneur certbot, assurez-vous de vérifier les journaux de service avec la commande docker-compose logs :

docker-compose logs service_name

Vous pouvez maintenant vérifier que vos certificats ont été montés sur le conteneur webserver avec docker-compose exec :

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

Si vos demandes de certificat ont abouti, vous verrez une sortie comme celle-ci :

Outputtotal 16
drwx------    3 root     root          4096 May 10 15:45 .
drwxr-xr-x    9 root     root          4096 May 10 15:45 ..
-rw-r--r--    1 root     root           740 May 10 15:45 README
drwxr-xr-x    2 root     root          4096 May 10 15:45 example.com

Maintenant que vous savez que votre demande aboutira, vous pouvez modifier la définition de service certbot pour supprimer l'indicateur --staging.

Ouvrez docker-compose.yml :

nano docker-compose.yml

Trouvez la section du fichier avec la définition de service certbot et remplacez le drapeau --staging dans l'option command par le drapeau --force-renewal, qui indiquera à Certbot que vous souhaitez demander un nouveau certificat avec les mêmes domaines qu'un certificat existant. La définition du service certbot ressemblera désormais à ceci :

~/wordpress/docker-compose.yml

...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...

Vous pouvez maintenant exécuter docker-compose up pour recréer le conteneur certbot. Nous inclurons également l'option --no-deps pour indiquer à Compose qu'il peut ignorer le démarrage du service webserver, puisqu'il est déjà en cours d'exécution :

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

Vous verrez une sortie indiquant que votre demande de certificat a réussi :

OutputRecreating 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 example.com
certbot      | http-01 challenge for www.example.com
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/example.com/fullchain.pem
certbot      |    Your key file has been saved at:
certbot      |    /etc/letsencrypt/live/example.com/privkey.pem
certbot      |    Your cert will expire on 2019-08-08. 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

Une fois vos certificats en place, vous pouvez passer à la modification de votre configuration Nginx pour inclure SSL.

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

L'activation de SSL dans notre configuration Nginx impliquera l'ajout d'une redirection HTTP vers HTTPS, la spécification de notre certificat SSL et des emplacements clés, et l'ajout de paramètres de sécurité et d'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

Avant de modifier le fichier de configuration lui-même, obtenons d'abord les paramètres de sécurité Nginx recommandés de Certbot en utilisant curl :

curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf

Cette commande enregistrera ces paramètres dans un fichier nommé options-ssl-nginx.conf, situé dans le répertoire nginx-conf.

Ensuite, supprimez le fichier de configuration Nginx que vous avez 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 des informations d'identification SSL, des protocoles et des en-têtes de sécurité. N'oubliez pas de remplacer example.com par votre propre domaine :

~/wordpress/nginx-conf/nginx.conf

server {
        listen 80;
        listen [::]:80;

        server_name example.com www.example.com;

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

        location / {
                rewrite ^ https://$host$request_uri? permanent;
        }
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name example.com www.example.com;

        index index.php index.html index.htm;

        root /var/www/html;

        server_tokens off;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        include /etc/nginx/conf.d/options-ssl-nginx.conf;

        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;
        # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        # enable strict transport security only if you understand the implications

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

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress: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 HTTP spécifie la racine Web pour les demandes de renouvellement Certbot dans le répertoire .well-known/acme-challenge. Il inclut également une directive de réécriture qui dirige les requêtes HTTP vers le répertoire racine vers HTTPS.

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

Ce bloc inclut également notre certificat SSL et nos emplacements de clé, ainsi que les paramètres de sécurité Certbot recommandés que nous avons enregistrés dans nginx-conf/options-ssl-nginx.conf.

De plus, nous avons inclus des en-têtes de sécurité qui nous permettront d'obtenir des notes A sur des éléments tels que les sites de test de serveur SSL Labs et Security Headers. Ces en-têtes incluent X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy, et X-XSS-Protection. L'en-tête HTTP Strict Transport Security (HSTS) est commenté - activez-le uniquement si vous comprenez les implications et avez évalué sa fonctionnalité "preload".

Nos directives root et index sont également situées dans ce bloc, tout comme le reste des blocs d'emplacement spécifiques à WordPress abordés dans Étape 1.

Une fois que vous avez terminé l'édition, enregistrez et fermez le fichier.

Avant de recréer le service webserver, vous devrez ajouter un mappage de port 443 à votre définition de service webserver.

Ouvrez votre fichier docker-compose.yml :

nano docker-compose.yml

Dans la définition de service webserver, ajoutez le mappage de port suivant :

~/wordpress/docker-compose.yml

...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

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

~/wordpress/docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes: 
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress:
    depends_on: 
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com

volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  

Enregistrez et fermez le fichier lorsque vous avez terminé l'édition.

Recréez le service webserver :

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

Vérifiez vos services avec docker-compose ps :

docker-compose ps

Vous devriez voir une sortie indiquant que vos services db, wordpress et webserver sont en cours d'exécution :

Output  Name                 Command               State                     Ports                  
----------------------------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0                                           
db          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
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp    

Avec vos conteneurs en cours d'exécution, vous pouvez maintenant terminer votre installation WordPress via l'interface Web.

Étape 6 - Terminer l'installation via l'interface Web

Avec nos conteneurs en cours d'exécution, nous pouvons terminer l'installation via l'interface Web WordPress.

Dans votre navigateur Web, accédez au domaine de votre serveur. N'oubliez pas de remplacer example.com ici par votre propre nom de domaine :

https://example.com

Sélectionnez la langue que vous souhaitez utiliser :

Après avoir cliqué sur Continuer, vous arriverez sur la page de configuration principale, où vous devrez choisir un nom pour votre site et un nom d'utilisateur. C'est une bonne idée de choisir ici un nom d'utilisateur mémorable (plutôt que "admin") et un mot de passe fort. Vous pouvez utiliser le mot de passe généré automatiquement par WordPress ou créer le vôtre.

Enfin, vous devrez entrer votre adresse e-mail et décider si vous souhaitez ou non décourager les moteurs de recherche d'indexer votre site :

En cliquant sur Installer WordPress en bas de la page, vous serez redirigé vers une invite de connexion :

Une fois connecté, vous aurez accès au tableau de bord d'administration WordPress :

Une fois votre installation WordPress terminée, vous pouvez maintenant prendre des mesures pour vous assurer que vos certificats SSL se renouvelleront automatiquement.

Étape 7 — Renouvellement des certificats

Les certificats Let's Encrypt sont valides pendant 90 jours, vous voudrez donc mettre en place un processus de renouvellement automatisé pour vous assurer qu'ils n'expirent pas. Une façon de procéder consiste à créer une tâche avec l'utilitaire de planification cron. Dans ce cas, nous allons créer une tâche cron pour exécuter périodiquement un script qui renouvellera nos certificats et rechargera notre configuration Nginx.

Commencez par ouvrir un script appelé ssl_renew.sh :

nano ssl_renew.sh

Ajoutez le code suivant au script pour renouveler vos certificats et recharger la configuration de votre serveur Web. N'oubliez pas de remplacer ici l'exemple de nom d'utilisateur par votre propre nom d'utilisateur non root :

~/wordpress/ssl_renew.sh

#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/sammy/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af

Ce script affecte d'abord le binaire docker-compose à une variable appelée COMPOSE, et spécifie l'option --no-ansi, qui exécutera les commandes docker-compose sans contrôle ANSI caractères. Il fait ensuite la même chose avec le binaire docker. Enfin, il passe au répertoire du projet ~/wordpress et exécute les commandes docker-compose suivantes :

  • docker-compose run : Cela démarrera un conteneur certbot et remplacera le command fourni 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. Nous avons inclus l'option --dry-run ici pour tester notre script.
  • docker-compose kill : cela enverra un signal SIGHUP au conteneur webserver pour recharger la configuration Nginx. Pour plus d'informations sur l'utilisation de ce processus pour recharger votre configuration Nginx, veuillez consulter ce billet de blog Docker sur le déploiement de l'image Nginx officielle avec Docker.

Il exécute ensuite docker system prune pour supprimer tous les conteneurs et images inutilisés.

Fermez le fichier lorsque vous avez terminé l'édition. Rendez-le exécutable :

chmod +x ssl_renew.sh

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

sudo crontab -e 

Si c'est la première fois que vous modifiez ce fichier, il vous sera demandé de choisir un éditeur :

Outputno crontab for root - using an empty one

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]:
...

En bas du fichier, ajoutez la ligne suivante :

crontab

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

Cela définira l'intervalle de travail à toutes les cinq minutes, afin que vous puissiez tester si votre demande de renouvellement a fonctionné ou non comme prévu. Nous avons également créé un fichier journal, cron.log, pour enregistrer la sortie pertinente de la tâche.

Après cinq minutes, vérifiez cron.log pour voir si la demande de renouvellement a réussi ou non :

tail -f /var/log/cron.log

Vous devriez voir une sortie confirmant un renouvellement réussi :

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/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Vous pouvez maintenant modifier le fichier crontab pour définir un intervalle quotidien. Pour exécuter le script tous les jours à midi, par exemple, vous modifieriez la dernière ligne du fichier pour qu'elle ressemble à ceci :

crontab

...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1

Vous voudrez également supprimer l'option --dry-run de votre script ssl_renew.sh :

~/wordpress/ssl_renew.sh

#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/sammy/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af

Votre travail cron garantira que vos certificats Let's Encrypt n'arrivent pas à expiration en les renouvelant lorsqu'ils sont éligibles. Vous pouvez également configurer la rotation des journaux avec l'utilitaire Logrotate pour faire pivoter et compresser vos fichiers journaux.

Conclusion

Dans ce didacticiel, vous avez utilisé Docker Compose pour créer une installation WordPress avec un serveur Web Nginx. Dans le cadre de ce workflow, vous avez obtenu des certificats TLS/SSL pour le domaine que vous souhaitez associer à votre site WordPress. De plus, vous avez créé une tâche cron pour renouveler ces certificats si nécessaire.

Comme étapes supplémentaires pour améliorer les performances et la redondance du site, vous pouvez consulter les articles suivants sur la livraison et la sauvegarde des ressources WordPress :

Si vous souhaitez explorer un flux de travail conteneurisé avec Kubernetes, vous pouvez également consulter :