Comment sécuriser une application Node.js conteneurisée avec Nginx, Let’s Encrypt et Docker Compose

introduction

Il existe plusieurs façons d'améliorer la flexibilité et la sécurité de votre applicationNode.js. L'utilisation d'unreverse proxy commeNginx vous offre la possibilité d'équilibrer la charge des requêtes, de mettre en cache le contenu statique et d'implémenterTransport Layer Security (TLS). L'activation du protocole HTTPS chiffré sur votre serveur garantit la sécurité de la communication vers et depuis votre application.

L'implémentation d'un proxy inverse avec TLS / SSL sur des conteneurs implique un ensemble de procédures différent de celui utilisé directement sur un système d'exploitation hôte. Par exemple, si vous obteniez des certificats deLet’s Encrypt pour une application exécutée sur un serveur, vous installeriez le logiciel requis directement sur votre hôte. Les conteneurs vous permettent d'adopter une approche différente. À l'aide deDocker Compose, vous pouvez créer des conteneurs pour votre application, votre serveur Web et lesCertbot client qui vous permettront d'obtenir vos certificats. En suivant ces étapes, vous pouvez tirer parti de la modularité et de la portabilité d'un flux de travail conteneurisé.

Dans ce tutoriel, vous allez déployer une application Node.js avec un proxy inverse Nginx à l'aide de Docker Compose. Vous obtiendrez des certificats TLS / SSL pour le domaine associé à votre application et vous vous assurerez qu'il reçoit une cote de sécurité élevée deSSL Labs. Enfin, vous mettrez en place un jobcron pour renouveler vos certificats afin que votre domaine reste sécurisé.

Conditions préalables

Pour suivre ce tutoriel, vous aurez besoin de:

  • Un serveur Ubuntu 18.04, un utilisateur non root avec les privilègessudo et un pare-feu actif. Pour savoir comment les configurer, veuillez consulter ceInitial Server Setup guide.

  • Docker et Docker Compose sont installés sur votre serveur. Pour obtenir des conseils sur l'installation de Docker, suivez les étapes 1 et 2 deHow To Install and Use Docker on Ubuntu 18.04. Pour obtenir des conseils sur l'installation de Compose, suivez l'étape 1 deHow To Install Docker Compose on Ubuntu 18.04.

  • Un nom de domaine enregistré. Ce didacticiel utiliseraexample.com partout. Vous pouvez en obtenir un gratuitement chezFreenom ou utiliser le registraire de domaine de votre choix.

  • Les deux enregistrements DNS suivants sont configurés pour votre serveur. Vous pouvez suivrethis introduction to DigitalOcean DNS pour savoir comment les ajouter à un compte DigitalOcean, si c'est ce que vous utilisez:

    • Un enregistrement A avecexample.com pointant vers l'adresse IP publique de votre serveur.

    • Un enregistrement A avecwww.example.com pointant vers l'adresse IP publique de votre serveur.

[[step-1 -—- cloning-and-testing-the-node-application]] == Étape 1 - Clonage et test de l'application de nœud

Dans un premier temps, nous clonerons le référentiel avec le code d'application Node, qui comprend le fichier Docker que nous allons utiliser pour créer notre image d'application avec Compose. Nous pouvons d'abord tester l'application en la construisant et en l'exécutant avec lesdocker run command, sans proxy inverse ni SSL.

Dans le répertoire personnel de votre utilisateur non root, clonez lesnodejs-image-demo repository à partir desDigitalOcean Community GitHub account. Ce référentiel comprend le code de la configuration décrite dansHow To Build a Node.js Application with Docker.

Clonez le référentiel dans un répertoire appelénode_project:

git clone https://github.com/do-community/nodejs-image-demo.git node_project

Accédez au répertoirenode_project:

cd  node_project

Dans ce répertoire, il y a un Dockerfile qui contient des instructions pour créer une application Node à l'aide desDocker node:10 image et du contenu de votre répertoire de projet actuel. Vous pouvez consulter le contenu du fichier Dockerfile en tapant:

cat Dockerfile
OutputFROM node:10-alpine

RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app

WORKDIR /home/node/app

COPY package*.json ./

USER node

RUN npm install

COPY --chown=node:node . .

EXPOSE 8080

CMD [ "node", "app.js" ]

Ces instructions créent une image Node en copiant le code du projet du répertoire courant vers le conteneur et en installant les dépendances avecnpm install. Ils tirent également parti descaching and image layering de Docker en séparant la copie depackage.json etpackage-lock.json, contenant les dépendances répertoriées du projet, de la copie du reste du code de l'application. Enfin, les instructions spécifient que le conteneur sera exécuté en tant qu'utilisateur non root denode avec les autorisations appropriées définies sur le code de l'application et les répertoiresnode_modules.

Pour plus d'informations sur les bonnes pratiques de ce fichier Dockerfile et de l'image de nœud, consultez la discussion complète dansStep 3 of How To Build a Node.js Application with Docker.

Pour tester l'application sans SSL, vous pouvez créer et baliser l'image à l'aide dedocker build et de l'indicateur-t. Nous appellerons l'imagenode-demo, mais vous êtes libre de lui donner un autre nom:

docker build -t node-demo .

Une fois le processus de construction terminé, vous pouvez lister vos images avecdocker images:

docker images

Vous verrez la sortie suivante, confirmant la construction de l'image de l'application:

OutputREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node-demo           latest              23961524051d        7 seconds ago       73MB
node                10-alpine           8a752d5af4ce        3 weeks ago         70.7MB

Ensuite, créez le conteneur avecdocker run. Nous allons inclure trois drapeaux avec cette commande:

  • -p: Ceci publie le port sur le conteneur et le mappe à un port sur notre hôte. Nous utiliserons le port80 sur l'hôte, mais vous devriez vous sentir libre de le modifier si nécessaire si vous avez un autre processus en cours d'exécution sur ce port. Pour plus d'informations sur la façon dont cela fonctionne, consultez cette discussion dans la documentation Docker surport binding.

  • -d: Ceci exécute le conteneur en arrière-plan.

  • --name: Cela nous permet de donner au conteneur un nom mémorable.

Exécutez la commande suivante pour construire le conteneur:

docker run --name node-demo -p 80:8080 -d node-demo

Inspectez vos conteneurs en cours d'exécution avecdocker ps:

docker ps

Vous verrez une sortie confirmant que votre conteneur d'application est en cours d'exécution:

OutputCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
4133b72391da        node-demo           "node app.js"       17 seconds ago      Up 16 seconds       0.0.0.0:80->8080/tcp   node-demo

Vous pouvez maintenant visiter votre domaine pour tester votre configuration:http://example.com. N'oubliez pas de remplacerexample.com par votre propre nom de domaine. Votre application affichera la page de destination suivante:

Application Landing Page

Maintenant que vous avez testé l'application, vous pouvez arrêter le conteneur et supprimer les images. Utilisez à nouveaudocker ps pour obtenir vosCONTAINER ID:

docker ps
OutputCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
4133b72391da        node-demo           "node app.js"       17 seconds ago      Up 16 seconds       0.0.0.0:80->8080/tcp   node-demo

Arrêtez le conteneur avecdocker stop. Assurez-vous de remplacer lesCONTAINER ID listés ici par votre propre applicationCONTAINER ID:

docker stop 4133b72391da

Vous pouvez maintenant supprimer le conteneur arrêté et toutes les images, y compris les images inutilisées et pendantes, avecdocker system prune et l'indicateur-a:

docker system prune -a

Tapezy lorsque vous y êtes invité dans la sortie pour confirmer que vous souhaitez supprimer le conteneur et les images arrêtés. Sachez que cela supprimera également votre cache de construction.

Avec votre image d'application testée, vous pouvez construire le reste de votre configuration avec Docker Compose.

[[step-2 -—- defining-the-web-server-configuration]] == Étape 2 - Définition de la configuration du serveur Web

Avec notre application Dockerfile en place, nous pouvons créer un fichier de configuration pour exécuter notre conteneur Nginx. Nous commencerons par une configuration minimale qui inclura notre nom de domaine,document root, les informations de proxy et un bloc d'emplacement pour diriger les requêtes de Certbot vers le répertoire.well-known, où il placera un fichier temporaire pour valider que le DNS de notre domaine est résolu par notre serveur.

Tout d’abord, créez un répertoire dans le répertoire du projet actuel pour le fichier de configuration:

mkdir nginx-conf

Ouvrez le fichier avecnano ou votre éditeur préféré:

nano nginx-conf/nginx.conf

Ajoutez le bloc serveur suivant aux requêtes des utilisateurs proxy vers votre conteneur d'application Node et pour diriger les requêtes de Certbot vers le répertoire.well-known. Assurez-vous de remplacerexample.com par votre propre nom de domaine:

~/node_project/nginx-conf/nginx.conf

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

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        server_name example.com www.example.com;

        location / {
                proxy_pass http://nodejs:8080;
        }

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

Ce bloc serveur nous permettra de démarrer le conteneur Nginx en tant que proxy inverse, ce qui permettra de transmettre les demandes à notre conteneur d'applications Node. Cela nous permettra également d'utiliser leswebroot plugin de Certbot pour obtenir des certificats pour notre domaine. Ce plugin dépend duHTTP-01 validation method, 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é.

Une fois que vous avez terminé, enregistrez et fermez le fichier. Pour en savoir plus sur le serveur Nginx et les algorithmes de bloc d'emplacement, veuillez consulter cet article surUnderstanding Nginx Server and Location Block Selection Algorithms.

Une fois les détails de configuration du serveur Web en place, nous pouvons passer à la création de notre fichierdocker-compose.yml, ce qui nous permettra de créer nos services d'application et le conteneur Certbot que nous utiliserons pour obtenir nos certificats.

[[step-3 -—- creation-the-docker-compose-file]] == Étape 3 - Création du fichier Docker Compose

Le fichierdocker-compose.yml définira nos services, y compris l'application Node et le serveur Web. Il spécifiera des détails tels que les volumes nommés, qui seront essentiels au partage des informations d'identification SSL entre les conteneurs, ainsi que des informations sur le réseau et les ports. Cela nous permettra également de spécifier des commandes spécifiques à exécuter lors de la création de nos conteneurs. Ce fichier est la ressource centrale qui définira comment nos services fonctionneront ensemble.

Ouvrez le fichier dans votre répertoire actuel:

nano docker-compose.yml

Tout d’abord, définissez le service d’application:

~/node_project/docker-compose.yml

version: '3'

services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped

La définition du servicenodejs comprend les éléments suivants:

  • build: Ceci définit les options de configuration, y compris lescontext etdockerfile, qui seront appliquées lorsque Compose crée l'image de l'application. Si vous vouliez utiliser une image existante d'un registre commeDocker Hub, vous pouvez utiliser lesimage instruction à la place, avec des informations sur votre nom d'utilisateur, votre référentiel et votre balise d'image.

  • context: Ceci définit le contexte de construction pour la construction d'image d'application. Dans ce cas, il s’agit du répertoire du projet en cours.

  • dockerfile: Ceci spécifie le Dockerfile que Compose utilisera pour la construction - le Dockerfile que vous avez regardé dansStep 1.

  • image,container_name: ils appliquent des noms à l'image et au conteneur.

  • restart: Ceci définit la politique de redémarrage. La valeur par défaut estno, mais nous avons configuré le conteneur pour qu'il redémarre à moins qu'il ne soit arrêté.

Notez que nous n'incluons pas de montages de liaison avec ce service, car notre configuration est axée sur le déploiement plutôt que sur le développement. Pour plus d'informations, veuillez consulter la documentation Docker surbind mounts etvolumes.

Pour permettre la communication entre l'application et les conteneurs du serveur Web, nous ajouterons également un réseau de pont appeléapp-network sous la définition de redémarrage:

~/node_project/docker-compose.yml

services:
  nodejs:
...
    networks:
      - app-network

Un tel réseau de pont défini par l'utilisateur permet la communication entre les conteneurs du même hôte démon Docker. Cela simplifie le trafic et la communication au sein de votre application, car il ouvre tous les ports entre les conteneurs sur le même réseau de pont, sans exposer aucun port au monde extérieur. Ainsi, vous pouvez sélectionner uniquement les ports dont vous avez besoin pour exposer vos services frontend.

Ensuite, définissez le servicewebserver:

~/node_project/docker-compose.yml

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

Certains des paramètres que nous avons définis pour le servicenodejs restent les mêmes, mais nous avons également apporté les modifications suivantes:

  • image: cela indique à Compose d'extraire les derniersAlpine-basedNginx image de Docker Hub. Pour plus d'informations sur les imagesalpine, veuillez consulter l'étape 3 deHow To Build a Node.js Application with Docker.

  • ports: Cela expose le port80 pour activer les options de configuration que nous avons définies dans notre configuration Nginx.

Nous avons également spécifié les volumes nommés et les montages de liaison suivants:

  • web-root:/var/www/html: Cela ajoutera les éléments statiques de notre site, copiés sur un volume appeléweb-root, dans le répertoire/var/www/html du conteneur.

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

  • certbot-etc:/etc/letsencrypt: Cela montera les certificats et les clés Let’s Encrypt pertinents pour notre domaine dans le répertoire approprié du conteneur.

  • certbot-var:/var/lib/letsencrypt: Ceci monte le répertoire de travail par défaut de Let’s Encrypt dans le répertoire approprié sur le conteneur.

Ensuite, ajoutez les options de configuration pour le conteneurcertbot. Assurez-vous de remplacer le domaine et les informations de courrier électronique par votre propre nom de domaine et votre adresse électronique de contact:

~/node_project/docker-compose.yml

...
  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - web-root:/var/www/html
    depends_on:
      - webserver
    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 lescertbot/certbot image 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é danscertbot-etc, le répertoire de travail Let’s Encrypt danscertbot-var et le code d’application dansweb-root.

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

Nous avons également inclus une optioncommand qui spécifie la commande à exécuter au démarrage du conteneur. Il inclut la sous-commandecertonly avec les options suivantes:

  • --webroot: Ceci indique à Certbot d'utiliser le plugin webroot pour placer les fichiers dans le dossier webroot pour l'authentification.

  • --webroot-path: Ceci spécifie le chemin du répertoire webroot.

  • --email: votre adresse e-mail préférée pour l'enregistrement et la récupération.

  • --agree-tos: ceci indique que vous acceptez lesACME’s Subscriber Agreement.

  • --no-eff-email: Cela indique à Certbot que vous ne souhaitez pas partager votre email avec lesElectronic Frontier Foundation (EFF). N'hésitez pas à l'omettre si vous préférez.

  • --staging: cela indique à Certbot que vous souhaitez utiliser l’environnement de préparation 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 les limites possibles des demandes de domaine. Pour plus d’informations sur ces limites, veuillez consulter lesrate limits documentation 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 inclusexample.com etwww.example.com. Assurez-vous de les remplacer par vos propres préférences de domaine.

Enfin, ajoutez les définitions de volume et de réseau. Assurez-vous de remplacer le nom d'utilisateur ici par votre propre utilisateur non root:

~/node_project/docker-compose.yml

...
volumes:
  certbot-etc:
  certbot-var:
  web-root:
    driver: local
    driver_opts:
      type: none
      device: /home/sammy/node_project/views/
      o: bind

networks:
  app-network:
    driver: bridge

Nos volumes nommés incluent notre certificat Certbot et les volumes du répertoire de travail, ainsi que le volume des actifs statiques de notre site,web-root. Dans la plupart des cas, le pilote par défaut pour les volumes Docker est le pilotelocal, qui sous Linux accepte des options similaires auxmount command. Grâce à cela, nous sommes en mesure de spécifier une liste d'options de pilote avecdriver_opts qui montent le répertoireviews sur l'hôte, qui contient les actifs statiques de notre application, sur le volume au moment de l'exécution. Le contenu du répertoire peut ensuite être partagé entre les conteneurs. Pour plus d'informations sur le contenu du répertoireviews, veuillez consulterStep 2 of How To Build a Node.js Application with Docker.

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

~/node_project/docker-compose.yml

version: '3'

services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped
    networks:
      - app-network

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

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - web-root:/var/www/html
    depends_on:
      - webserver
    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:
  certbot-var:
  web-root:
    driver: local
    driver_opts:
      type: none
      device: /home/sammy/node_project/views/
      o: bind

networks:
  app-network:
    driver: bridge

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

[[step-4 -—- getting-ssl-certificates-and-credentials]] == Étape 4 - Obtention des certificats SSL et des informations d'identification

Nous pouvons démarrer nos conteneurs avecdocker-compose up, qui créera et exécutera nos conteneurs et services dans l'ordre que nous avons spécifié. Si nos demandes de domaine aboutissent, nous verrons l'état de sortie correct dans notre sortie et les bons certificats montés dans le dossier/etc/letsencrypt/live sur le conteneurwebserver.

Créez les services avecdocker-compose up et l'indicateur-d, qui exécuteront les conteneursnodejs etwebserver en arrière-plan:

docker-compose up -d

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

OutputCreating nodejs ... done
Creating webserver ... done
Creating certbot   ... done

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

docker-compose ps

Si tout a réussi, vos servicesnodejs etwebserver devraient êtreUp et le conteneurcertbot sera sorti avec un message d'état0:

Output  Name                 Command               State          Ports
------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0
nodejs      node app.js                      Up       8080/tcp
webserver   nginx -g daemon off;             Up       0.0.0.0:80->80/tcp

Si vous voyez autre chose queUp dans la colonneState pour les servicesnodejs etwebserver, ou un état de sortie autre que0 pourcertbot) s, assurez-vous de vérifier les journaux de service avec la commandedocker-compose logs:

docker-compose logs service_name

Vous pouvez maintenant vérifier que vos informations d'identification ont été montées dans le conteneurwebserver avecdocker-compose exec:

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

Si votre demande a abouti, vous verrez une sortie comme ceci:

Outputtotal 16
drwx------ 3 root root 4096 Dec 23 16:48 .
drwxr-xr-x 9 root root 4096 Dec 23 16:48 ..
-rw-r--r-- 1 root root  740 Dec 23 16:48 README
drwxr-xr-x 2 root root 4096 Dec 23 16:48 example.com

Maintenant que vous savez que votre demande sera réussie, vous pouvez modifier la définition du servicecertbot pour supprimer l'indicateur--staging.

Ouvrirdocker-compose.yml:

nano docker-compose.yml

Trouvez la section du fichier avec la définition du servicecertbot, et remplacez l'indicateur--staging dans l'optioncommand par l'indicateur--force-renewal, qui indiquera à Certbot que vous voulez demander un nouveau certificat avec les mêmes domaines qu'un certificat existant. La définition du servicecertbot devrait maintenant ressembler à ceci:

~/node_project/docker-compose.yml

...
  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - web-root:/var/www/html
    depends_on:
      - webserver
    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écuterdocker-compose up pour recréer le conteneurcertbot et ses volumes pertinents. Nous inclurons également l'option--no-deps pour indiquer à Compose qu'il peut ignorer le démarrage du servicewebserver, car 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 abouti:

Outputcertbot      | 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-03-26. 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 modifier la configuration de Nginx afin d’inclure SSL.

[[step-5 -—- modification-the-web-server-configuration-and-service-definition]] == Étape 5 - Modification de la configuration du serveur Web et de la définition du service

L'activation de SSL dans notre configuration Nginx implique l'ajout d'une redirection HTTP vers HTTPS et la spécification de notre certificat SSL et de l'emplacement des clés. Cela impliquera également de spécifier notre groupe Diffie-Hellman, que nous utiliserons pourPerfect Forward Secrecy.

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

docker-compose stop webserver

Ensuite, créez un répertoire dans votre répertoire de projet actuel pour votre clé Diffie-Hellman:

mkdir dhparam

Générez votre clé avec lesopenssl command:

sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048

Il faudra quelques instants pour générer la clé.

Pour ajouter les informations Diffie-Hellman et SSL pertinentes à votre configuration Nginx, commencez par supprimer 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 ajouter les informations d'identification SSL, les protocoles et les en-têtes de sécurité. N'oubliez pas de remplacerexample.com par votre propre domaine:

~/node_project/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;

        server_tokens off;

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

        ssl_buffer_size 8k;

        ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;

        ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
        ssl_prefer_server_ciphers on;

        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

        ssl_ecdh_curve secp384r1;
        ssl_session_tickets off;

        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8;

        location / {
                try_files $uri @nodejs;
        }

        location @nodejs {
                proxy_pass http://nodejs:8080;
                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
        }

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
}

Le bloc de serveur HTTP spécifie la racine Web pour les demandes de renouvellement Certbot vers le répertoire.well-known/acme-challenge. Il inclut également unrewrite directive qui dirige les requêtes HTTP vers le répertoire racine vers HTTPS.

Le bloc serveur HTTPS active lesssl ethttp2. 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 àHow To Set Up Nginx with HTTP/2 Support on Ubuntu 18.04. Ce bloc comprend également une série d'options pour vous assurer que vous utilisez les protocoles et les chiffrements SSL les plus récents et que l'agrafage OSCP est activé. L'agrafage OSCP vous permet d'offrir une réponse horodatée de voscertificate authority pendant lesTLS handshakeinitiaux, ce qui peut accélérer le processus d'authentification.

Le bloc spécifie également vos informations d'identification SSL et Diffie-Hellman et les emplacements de clé.

Enfin, nous avons déplacé les informations de passage du proxy vers ce bloc, y compris un bloc d'emplacement avec une directivetry_files, des requêtes pointant vers notre conteneur d'application aliasé Node.js, et un bloc d'emplacement pour cet alias, qui comprend des en-têtes de sécurité cela nous permettra d'obtenir des notes deA sur des choses comme les sites de test des serveursSSL Labs etSecurity Headers. Ces en-têtes incluentX-Frame-Options,X-Content-Type-Options,Referrer Policy,Content-Security-Policy etX-XSS-Protection. L'en-têteHTTP Strict Transport Security (HSTS) est commenté - activez ceci uniquement si vous comprenez les implications et avez évalué ses“preload” functionality.

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

Avant de recréer le servicewebserver, vous devrez ajouter quelques éléments à la définition de service dans votre fichierdocker-compose.yml, y compris des informations de port pertinentes pour HTTPS et une définition de volume Diffie-Hellman.

Ouvrez le fichier:

nano docker-compose.yml

Dans la définition du servicewebserver, ajoutez le mappage de port suivant et le volume nommédhparam:

~/node_project/docker-compose.yml

...
 webserver:
    image: nginx:latest
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - web-root:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - dhparam:/etc/ssl/certs
    depends_on:
      - nodejs
    networks:
      - app-network

Ensuite, ajoutez le volumedhparam à vos définitionsvolumes:

~/node_project/docker-compose.yml

...
volumes:
  ...
  dhparam:
    driver: local
    driver_opts:
      type: none
      device: /home/sammy/node_project/dhparam/
      o: bind

Comme pour le volumeweb-root, le volumedhparam montera la clé Diffie-Hellman stockée sur l'hôte dans le conteneurwebserver.

Enregistrez et fermez le fichier une fois l’édition terminée.

Recréez le servicewebserver:

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

Vérifiez vos services avecdocker-compose ps:

docker-compose ps

Vous devriez voir une sortie indiquant que vos servicesnodejs etwebserver sont en cours d'exécution:

Output  Name                 Command               State                     Ports
----------------------------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0
nodejs      node app.js                      Up       8080/tcp
webserver   nginx -g daemon off;             Up       0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

Enfin, vous pouvez visiter votre domaine pour vous assurer que tout fonctionne comme prévu. Accédez àhttps://example.com dans votre navigateur, en veillant à remplacerexample.com par votre propre nom de domaine. Vous verrez la page de destination suivante:

Application Landing Page

Vous devriez également voir l'icône de cadenas dans l'indicateur de sécurité de votre navigateur. Si vous le souhaitez, vous pouvez accéder auxSSL Labs Server Test landing page ou auxSecurity Headers server test landing page. Les options de configuration que nous avons incluses devraient donner à votre site une note deAur les deux.

[[step-6 -—- renewing-certificates]] == Étape 6 - Renouvellement des certificats

Les certificats Let Encrypt sont valides pendant 90 jours. Par conséquent, vous souhaiterez configurer un processus de renouvellement automatisé pour éviter tout dépassement. Une façon de procéder consiste à créer un travail avec l'utilitaire de planificationcron. Dans ce cas, nous planifierons un travailcron en utilisant un script qui renouvellera nos certificats et rechargera notre configuration Nginx.

Ouvrez un script appeléssl_renew.sh dans le répertoire de votre projet:

nano ssl_renew.sh

Ajoutez le code suivant au script pour renouveler vos certificats et recharger la configuration de votre serveur Web:

~/node_project/ssl_renew.sh

#!/bin/bash

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

En plus de spécifier l'emplacement de notre binairedocker-compose, nous spécifions également l'emplacement de notre fichierdocker-compose.yml afin d'exécuter les commandesdocker-compose. Dans ce cas, nous utilisonsdocker-compose run pour démarrer un conteneurcertbot et pour remplacer lescommand fournis dans notre définition de service par un autre: la sous-commanderenew, qui renouvellera les certificats qui sont sur le point d'expirer. Nous avons inclus l'option--dry-run ici pour tester notre script.

Le script utilise ensuitedocker-compose kill pour envoyer unSIGHUP signal au conteneurwebserver pour recharger la configuration Nginx. Pour plus d'informations sur l'utilisation de ce processus pour recharger votre configuration Nginx, veuillez consulterthis Docker blog post on deploying the official Nginx image with Docker.

Fermez le fichier lorsque vous avez terminé vos modifications. Rendez-le exécutable:

chmod +x ssl_renew.sh

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

sudo crontab -e

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

crontab

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

Au bas du fichier, ajoutez la ligne suivante:

crontab

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

Cela définira l'intervalle des tâches toutes les cinq minutes afin que vous puissiez vérifier si votre demande de renouvellement a fonctionné 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érifiezcron.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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Killing webserver ... done

Vous pouvez maintenant modifier le fichiercrontab pour définir un intervalle quotidien. Pour exécuter le script tous les jours à midi, par exemple, vous devez modifier la dernière ligne du fichier pour ressembler à ceci:

crontab

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

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

~/node_project/ssl_renew.sh

#!/bin/bash

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

Votre missioncron garantira que vos certificats Let’s Encrypt ne sont pas périmés en les renouvelant lorsqu'ils sont éligibles. Vous pouvez égalementset up log rotation with the Logrotate utility pour faire pivoter et compresser vos fichiers journaux.

Conclusion

Vous avez utilisé des conteneurs pour configurer et exécuter une application Node avec un proxy inverse Nginx. Vous avez également sécurisé des certificats SSL pour le domaine de votre application et configuré une tâchecron pour renouveler ces certificats si nécessaire.

Si vous souhaitez en savoir plus sur les plugins Let’s Encrypt, veuillez consulter nos articles sur l’utilisation desNginx plugin ou desstandalone plugin.

Vous pouvez également en savoir plus sur Docker Compose en consultant les ressources suivantes:

LeCompose documentation est également une excellente ressource pour en savoir plus sur les applications multi-conteneurs.