One place for hosting & domains

      Comment dimensionner et sécuriser une application Django avec Docker, Nginx et Let’s Encrypt


      Introduction

      Dans les environnements basés sur le cloud, il existe de multiples façons de faire évoluer et de sécuriser une application Django. En dimensionnant horizontalement et en exécutant plusieurs copies de votre application, vous pouvez construire un système plus tolérant aux défauts et très disponible, tout en augmentant également son débit, afin que les demandes puissent être traitées simultanément. Une manière de faire évoluer à l’échelle horizontale une application Django consiste à fournir des serveurs d’application supplémentaires qui exécutent votre application Django et son serveur HTTP WSGI (comme Gunicorn ou uWSGI). Pour acheminer et distribuer les demandes entrantes sur cet ensemble de serveurs d’application, vous pouvez utiliser un équilibreur de charge et un proxy inverse comme Nginx. Nginx peut également mettre en cache le contenu statique et mettre fin aux connexions TLS (Transport Layer Security Security), utilisées pour fournir des connexions HTTPS, et sécuriser les connexions à votre application.

      L’exécution de votre application Django et du proxy Nginx à l’intérieur des conteneurs Docker garantit que ces composants se comportent de la même manière quel que soit l’environnement dans lequel ils sont déployés. De plus, les conteneurs fournissent de nombreuses fonctionnalités qui facilitent l’emballage et la configuration de votre application.

      Dans ce tutoriel, vous allez à mettre l’échelle horizontalement une application de sondages pour Django et Gunicorn conteneurisé en fournissant deux serveurs d’application qui exécuteront chacune une copie d’un conteneur d’application Django et Gunicorn.

      Vous allez également activer HTTPS, en fournissant et en configurant un troisième serveur proxy qui exécutera un conteneur proxy inverse Nginx et un conteneur client Certbot. Certbot fournira des certificats TLS pour Nginx à partir de l’autorité de certification Let’s Encrypt. Cela garantira que votre site bénéficie d’une cote de sécurité élevée de la part de SSL Labs. Ce serveur proxy recevra toutes les demandes externes de votre application et sera en face des deux serveurs d’application Django en amont. Enfin, vous allez renforcer ce système distribué en limitant l’accès externe au serveur proxy uniquement.

      Conditions préalables

      Pour suivre ce tutoriel, vous aurez besoin de :

      • Trois serveurs Ubuntu 18.04 :

        • Deux serveurs seront des serveurs d’application, utilisés pour exécuter vos applications Django et Gunicorn.
        • Un serveur sera un serveur proxy utilisé pour exécuter Nginx et Certbot.
        • Tous devraient avoir un non-root user avec des privilèges sudo et un pare-feu actif. Pour savoir comment les configurer, veuillez consulter le présent Guide de configuration initiale du serveur.
      • Docker installé sur les trois serveurs. Pour obtenir de l’aide sur l’installation de Docker, suivez les Étapes 1 et 2 de Comment installer et utiliser Docker sur Ubuntu 18.04.

      • Un nom de domaine enregistré. Ce tutoriel utilisera your_domain.comtout au long. Vous pouvez en obtenir un gratuitement sur Freenom ou utiliser le registre de domaine de votre choix.

      • Un enregistrement DNS A avec your_domain.com pointant sur l’adresse IP publique de votre serveur proxy. Vous pouvez suivre cette introduction au DNS DigitalOcean pour plus de détails sur la façon de l’ajouter à un compte DigitalOcean, si c’est ce que vous utilisez.

      • Un object storage bucket S3 comme un espace DigitalOceanpour stocker les fichiers statiques de votre projet Django et un ensemble de clés d’accès pour cet espace. Pour apprendre à créer un espace, consultez la documentation produit Comment créer des espaces. Pour apprendre à créer des clés d’accès pour les espaces, consultez Partager l’accès aux espaces avec les clés d’accès. Avec des modifications mineures, vous pouvez utiliser n’importe quel service de stockage d’objets que le plugin django-storages prend en charge.

      • Une instance serveur PostgreSQL, une base de données et un utilisateur pour votre application Django. Avec des modifications mineures, vous pouvez utiliser n’importe quelle base de données que Django prend en charge.

      Étape 1 — Configuration du premier serveur d’application Django

      Pour commencer, nous allons cloner le référentiel d’application Django sur le premier serveur d’application. Ensuite, nous allons configurer et construire l’image de l’application Docker, et tester l’application en exécutant le conteneur Django.

      Remarque : si vous continuez en suivant Comment construire une application Django et Gunicorn avec Docker, vous aurez déjà terminé Étape 1 et pouvez passer à l’étape 2 pour configurer le deuxième serveur d’application.

      Commencez par vous connecter au premier des deux serveurs d’application Django et utilisez git pour cloner la branche polls-docker du référentiel GitHub du tutoriel des applications Django Polls. Ce référentiel contient le code pour l’application de sondages dans la documentation de Django. La branche de polls-docker contient une version Dockerisée de l’application de sondage. Pour savoir comment l’application de sondage a été modifiée pour fonctionner efficacement dans un environnement conteneurisé, consultez Comment construire une application Django et Gunicorn avec Docker.

      • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

      Naviguez dans le répertoire django-polls :

      cd django-polls
      

      Ce répertoire contient le code Python de l’application Django, un Dockerfile que Docker utilisera pour construire l’image du conteneur, ainsi qu’un fichier env contenant une liste de variables d’environnement à passer dans l’environnement d’exécution du conteneur. Inspectez le Dockerfile à l’aide de cat :

      cat Dockerfile
      

      Output

      FROM python:3.7.4-alpine3.10 ADD django-polls/requirements.txt /app/requirements.txt RUN set -ex && apk add --no-cache --virtual .build-deps postgresql-dev build-base && python -m venv /env && /env/bin/pip install --upgrade pip && /env/bin/pip install --no-cache-dir -r /app/requirements.txt && runDeps="$(scanelf --needed --nobanner --recursive /env | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }' | sort -u | xargs -r apk info --installed | sort -u)" && apk add --virtual rundeps $runDeps && apk del .build-deps ADD django-polls /app WORKDIR /app ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH EXPOSE 8000 CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"]

      Ce Dockerfile utilise l’image Docker officielle de Python 3.7.4 comme base, et installe les exigences du paquet Python de Django et Gunicorn, telles que définies dans le fichier django-polls/requirements.txt. Il supprime ensuite quelques fichiers de construction inutiles, copie le code de l’application dans l’image, et définit le PATH d’exécution. Enfin, il déclare que le port 8000 sera utilisé pour accepter les connexions de conteneurs entrantes, et exécute gunicorn avec 3 travailleurs, en écoutant sur le port 8000.

      Pour en savoir plus sur chacune des étapes de ce Dockerfile, consultez l’Étape 6 de Comment construire une application Django et Gunicorn avec Docker.

      Maintenant, construisez l’image à l’aide de docker build :

      Nous nommons l’image polls en utilisant le drapeau -t et passons dans le répertoire courant comme contexte de construction, l’ensemble de fichiers à faire référence lors de la construction de l’image.

      Après que Docker ait construit et étiqueté l’image, listez les images disponibles à l’aide de docker images :

      docker images
      

      Vous devriez voir l’image polls listée :

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE polls latest 80ec4f33aae1 2 weeks ago 197MB python 3.7.4-alpine3.10 f309434dea3a 8 months ago 98.7MB

      Avant de lancer le conteneur Django, nous devons configurer son environnement d’exécution à l’aide du fichier env présent dans le répertoire actuel. Ce fichier sera transmis dans la commande docker run utilisée pour exécuter le conteneur, et Docker injectera les variables d’environnement configurées dans l’environnement d’exécution du conteneur.

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

      nano env
      

      Nous allons configurer le fichier comme ceci, et vous devrez ajouter quelques valeurs supplémentaires comme indiqué ci-dessous.

      django-polls/env

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Remplissez les valeurs manquantes pour les clés suivantes :

      • DJANGO_SECRET_KEY : définissez cette valeur à une valeur unique et imprévisible, comme indiqué dans les docs de Django. Une méthode de génération de cette clé est fournie dans Ajustement des paramètres du tutoriel sur les applications Django dimensionnables.
      • DJANGO_ALLOWED_HOSTS: : cette variable sécurise l’application et prévient les attaques d’en-tête d’hôte HTTP. Pour les besoins de test, définissez cette variable à *, un joker qui correspondra à tous les hôtes. En production, vous devriez la définir sur your_domain.com. Pour en savoir plus sur ce paramètre Django, consultez les paramètres de base dans les docs Django.
      • DATABASE_USERNAME : définissez ce paramètre sur l’utilisateur de la base de données PostgreSQL créé dans les étapes préalables.
      • DATABASE_NAME : définissez ce paramètres sur polls ou le nom de la base de données PostgreSQL créée dans les étapes préalables.
      • DATABASE_PASSWORD : définissez ce paramètre sur le mot de passe de l’utilisateur PostgreSQL créé dans les étapes préalables.
      • DATABASE_HOST : définissez ce paramètre sur le nom d’hôte de votre base de données.
      • DATABASE_PORT : définissez ce paramètre sur le port de votre base de données.
      • STATIC_ACCESS_KEY_ID : définissez ce paramètre sur votre bucket S3 ou sur la clé d’accès à l’espace.
      • STATIC_ACCESS_KEY_ID : définissez ce paramètre sur votre bucket S3 ou sur la clé secrète d’accès à l’espace.
      • STATIC_BUCKET_NAME : définissez ce paramètre sur votre bucket S3 ou votre nom d’espace.
      • STATIC_ENDPOINT_URL : définissez ce paramètre sur le bucket S3 approprié ou l’URL de votre espace, par exemple https://space-name.nyc3.digitaloceanspaces.com si votre espace se trouve dans la région nyc3.

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

      Nous allons maintenant utiliser docker run pour remplacer le paramètre CMD dans le Dockerfile et créer le schéma de base de données à l’aide des commandes manage.py et manage.py migrate :

      docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"
      

      Nous lançons le container d’images polls:latest, nous passons dans le fichier variable d’environnement que nous venons de modifier, et remplacons la commande Dockerfile par sh -c "python manage.py makemigrations python manage.py image", qui créera le schéma de base de données défini par le code de l’application. Si vous exécutez cette opération pour la première fois, vous devriez voir ce qui suit :

      Output

      No changes detected Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying polls.0001_initial... OK Applying sessions.0001_initial... OK

      Cela indique que le schéma de base de données a été créé avec succès.

      Si vous exécutez migrate une, fois de plus, Django effectuera un no-op à moins que le schéma de base de données ait changé.

      Ensuite, nous allons exécuter une autre instance du conteneur de l’application et utiliser un shell interactif à l’intérieur de celui-ci pour créer un utilisateur administratif pour le projet Django.

      docker run -i -t --env-file env polls sh
      

      Vous obtiendrez une invite shell à l’intérieur du conteneur en cours d’exécution que vous pouvez utiliser pour créer l’utilisateur Django :

      python manage.py createsuperuser
      

      Entrez un nom d’utilisateur, une adresse email et un mot de passe pour votre utilisateur, et après avoir créé l’utilisateur, appuyez sur CTRL+D pour quitter le conteneur et le fermer.

      Enfin, nous allons générer les fichiers statiques pour l’application et les télécharger sur l’espace DigitalOcean à l’aide de collectstatic. Notez que cela peut prendre un peu de temps.

      docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"
      

      Une fois que ces fichiers sont générés et téléchargés, vous obtiendrez la sortie suivante.

      Output

      121 static files copied.

      Nous pouvons maintenant exécuter l’application :

      docker run --env-file env -p 80:8000 polls
      

      Output

      [2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0 [2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) [2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync [2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7 [2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8 [2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

      Ici, nous exécutons la commande par défaut définie dans le Dockerfile, gunicorn --bind :8000 --workers 3 mysite.wsgi:application, et exposons le port de conteneur 8000 afin que le port 80 sur le serveur Ubuntu soit mappé sur le port 8000 du conteneur polls.

      Vous devriez maintenant pouvoir naviguez jusqu’à l’application de sondages à l’aide de votre navigateur web en tapant : http://APP_SERVER_1_IP dans la barre d’URL. Comme il n’y a pas de route définie pour le chemin d’accès / , vous obtiendrez probablement une erreur de recherche 404 Page Not Found, qui est prévisible.

      Attention : Lorsque vous utilisez le pare-feu UFW avec Docker, Docker contourne les règles de pare-feu UFW, comme indiqué dans ce numéro de GitHub. Cela explique pourquoi vous avez accès au port 80 de votre serveur, même si vous n’avez pas explicitement créé de règle d’accès UFW dans aucune étape préalable. Dans l’Étape 5, nous aborderons cette faille de sécurité en corrigeant la configuration d’UFW. Si vous n’utilisez pas UFW et que vous utilisez les pare-feu Cloud de DigitalOcean, vous pouvez ignorer cet avertissement.

      Naviguez sur http://APP_SERVER_1_IP/polls pour voir l’interface de l’application de sondage :

      Interface des applications de sondage

      Pour voir l’interface administrative, allez à http://APP_SERVER_1_IP/admin. Vous devriez voir la fenêtre d’authentification de l’application de sondage :

      Page Auth admin des sondages

      Entrez le nom d’utilisateur administratif et le mot de passe que vous avez créé avec la commande createsuperuser.

      Après avoir été authentifié, vous pouvez accéder à l’interface administrative de l’application de sondage :

      Interface principale de l'administration de sondages

      Notez que les actifs statiques pour les applications d’administration et de sondage sont livrées directement depuis le stockage d’objets. Pour confirmer ceci, consultez Testing Spaces Static File Delivery.

      Lorsque vous avez terminé d’explorer, appuyez sur CTRL+C dans la fenêtre de terminal en exécutant le conteneur de Docker pour terminer le conteneur.

      Maintenant que vous avez confirmé que le conteneur d’application fonctionne comme prévu, vous pouvez l’exécuter en mode détaché, qui l’exécutera en arrière-plan et vous permettra de vous déconnecter de votre session SSH :

      docker run -d --rm --name polls --env-file env -p 80:8000 polls
      

      Le drapeau -d demande à Docker d’exécuter le conteneur en mode détaché, le drapeau -rm nettoie le système de fichiers du conteneur après la fermeture du conteneur, et nous donnons un nom aux sondages de conteneur.

      Déconnectez-vous du premier serveur d’application Django, et naviguez vers http://APP_SERVER_1_IP/polls pour confirmer que le conteneur fonctionne comme prévu.

      Maintenant que votre premier serveur d’application Django est opérationnel, vous pouvez configurer votre deuxième serveur d’application Django.

      Étape 2 — Configuration du deuxième serveur d’application Django

      Comme beaucoup de commandes pour configurer ce serveur seront les mêmes que celles de l’étape précédente, elles seront présentées ici sous forme abrégée. Veuillez consulter l’Étape 1 pour plus d’informations sur une commande particulière de cette étape.

      Commencez par vous connecter au deuxième serveur d’application Django.

      Clonez la branche polls-docker du référentiel GitHub django-polls :

      • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

      Naviguez dans le répertoire django-polls :

      cd django-polls
      

      Maintenant, construisez l’image à l’aide de docker build :

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

      nano env
      

      django-polls/env

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Remplissez les valeurs manquantes comme à l’Étape 1. Lorsque vous avez terminé les modifications, enregistrez et fermez le fichier.

      Enfin, exécutez le conteneur d’application en mode détaché :

      docker run -d --rm --name polls --env-file env -p 80:8000 polls
      

      Naviguez jusqu’à http://APP_SERVER_2_IP/polls pour confirmer que le conteneur fonctionne comme prévu. Vous pouvez vous déconnecter en toute sécurité du deuxième serveur d’application sans mettre fin à votre conteneur en cours d’exécution.

      Une fois les conteneurs d’application Django opérationnels, vous pouvez passer à la configuration du conteneur proxy inverse Nginx.

      Étape 3 — Configuration du conteneur Docker Nginx

      Nginx est un serveur web polyvalent qui offre un certain nombre de fonctionnalités, dont le proxy inverse, l’équilibrage de la charge et la mise en cache. Dans ce tutoriel, nous avons déchargé les ressources statiques de Django pour le stockage d’objets, nous n’utiliserons donc pas les capacités de mise en cache de Nginx. Cependant, nous utiliserons Nginx comme proxy inverse sur nos deux serveurs d’application Django de backend et distribuerons les demandes entrantes entre eux. En outre, Nginx effectuera la terminaison et la redirection TLS à l’aide d’un certificat TLS fourni par Certbot. Cela signifie qu’il forcera les clients à utiliser HTTPS, redirigeant les requêtes HTTPS vers le port 443. Il déchiffrera ensuite les requêtes HTTPS, puis les enverra par proxy aux serveurs Django en amont.

      Dans ce tutoriel, nous avons pris la décision de découpler les conteneurs Nginx des serveurs de backend. En fonction de votre cas d’utilisation, vous pouvez choisir d’exécuter le conteneur Nginx sur l’un des serveurs d’application Django, en envoyant les requêtes par proxy localement et ainsi que vers l’autre serveur Django. Une autre architecture possible serait d’exécuter deux conteneurs Nginx, un sur chaque serveur de backend avec un load balancer en cloud en avant. Chaque architecture présente différents avantages de sécurité et de performance, et vous devriez tester la charge de votre système pour découvrir les goulets d’étranglement. L’architecture flexible décrite dans ce tutoriel vous permet d’évaluer à la fois la couche d’application Django de backend et la couche proxy Nginx. Une fois que le conteneur Nginx unique devient un goulot d’étranglement, vous pouvez échelonner sur plusieurs proxies Nginx, et ajouter un load balancer en cloud ou un load balancer L4 rapide comme HAProxy.

      Une fois les deux serveurs d’applications Django en place, nous pouvons commencer à configurer le serveur proxy Nginx. Connectez-vous à votre serveur proxy et créez un répertoire appelé conf :

      mkdir conf
      

      Créez un fichier de configuration appelé nginx.conf à l’aide de nano ou de votre éditeur préféré :

      nano conf/nginx.conf
      

      Collez dans la configuration Nginx suivante :

      conf/nginx.conf

      
      upstream django {
          server APP_SERVER_1_IP;
          server APP_SERVER_2_IP;
      }
      
      server {
          listen 80 default_server;
          return 444;
      }
      
      server {
          listen 80;
          listen [::]:80;
          server_name your_domain.com;
          return 301 https://$server_name$request_uri;
      }
      
      server {
          listen 443 ssl http2;
          listen [::]:443 ssl http2;
          server_name your_domain.com;
      
          # SSL
          ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
      
          ssl_session_cache shared:le_nginx_SSL:10m;
          ssl_session_timeout 1440m;
          ssl_session_tickets off;
      
          ssl_protocols TLSv1.2 TLSv1.3;
          ssl_prefer_server_ciphers off;
      
          ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
      
          client_max_body_size 4G;
          keepalive_timeout 5;
      
              location / {
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                proxy_pass http://django;
              }
      
          location ^~ /.well-known/acme-challenge/ {
              root /var/www/html;
          }
      
      }
      

      Ces blocs upstream, server et location configurent Nginx pour rediriger les requêtes HTTP vers HTTPS, et et équilibrent la charge entre les deux serveurs d’applications Django configurés aux Étapes 1 et 2. Pour en savoir plus sur la structure du fichier de configuration Nginx, consultez cet article sur la compréhension de la structure du fichier de configuration Nginx et les contextes de configuration. En outre, cet article sur La compréhension des algorithmes de sélection des serveurs Nginx et des blocs de localisation peut être utile.

      Cette configuration a été assemblée à partir d’exemplesde fichiers de configuration fournis par Gunicorn, Cerbot et Nginx et est conçue comme une configuration Nginx minimale pour que cette architecture soit opérationnelle. L’adaptation de cette configuration Nginx dépasse la portée de cet article, mais vous pouvez utiliser un outil comme NGINXConfig pour générer des fichiers de configuration Nginx performants et sécurisés pour votre architecture.

      Le bloc upstream définit le groupe de serveurs utilisés pour les demandes de proxy à l’aide de la directive proxy_pass :

      conf/nginx.conf

      upstream django {
          server APP_SERVER_1_IP;
          server APP_SERVER_2_IP;
      }
      . . .
      

      Dans ce bloc, nous nommons le upstream django et incluons les adresses IP des deux serveurs d’application Django. Si les serveurs d’application fonctionnent sur DigitalOcean et que le réseau VPC est activé, vous devriez utiliser leurs adresses IP privées ici. Pour apprendre à activer le VPC Networking sur DigitalOcean, consultez Comment activer le VPC Networking sur les droplets existants.

      Le premier bloc server capture les demandes qui ne correspondent pas à votre domaine et met fin à la connexion. Par exemple, une requête HTTP directe vers l’adresse IP de votre serveur serait traitée par ce bloc :

      conf/nginx.conf

      . . .
      server {
          listen 80 default_server;
          return 444;
      }
      . . .
      

      Le bloc server suivant redirige les requêtes HTTP, vers votre domaine, à l’aide d’un redirect HTTP 301 redirect. Ces demandes sont ensuite traitées par le bloc server final :

      conf/nginx.conf

      . . .
      server {
          listen 80;
          listen [::]:80;
          server_name your_domain.com;
          return 301 https://$server_name$request_uri;
      }
      . . .
      

      Ces deux directives définissent les chemins d’accès au certificat TLS et à la clé secrète. Ceux-ci seront fournis à l’aide de Certbot et montés dans le conteneur Nginx à l’étape suivante.

      conf/nginx.conf

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

      Ces paramètres sont les valeurs par défaut de la sécurité SSL recommandées par Certbot. Pour en savoir plus sur ces questions, consultez le Module ngx_http_ssl_module dans les docs Nginx. Security/Server Side TLS de Mozilla est un autre guide utile que vous pouvez utiliser pour ajuster la configuration SSL.

      conf/nginx.conf

      . . .
          ssl_session_cache shared:le_nginx_SSL:10m;
          ssl_session_timeout 1440m;
          ssl_session_tickets off;
      
          ssl_protocols TLSv1.2 TLSv1.3;
          ssl_prefer_server_ciphers off;
      
          ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
      . . .
      

      Ces deux directives d’exemple de configuration Nginx de Gunicorn définissent la taille maximale autorisée du corps de requête client et attribuent le timeout pour les connexions keep-alive avec le client. Nginx fermera les connexions avec le client après keepalive_timeout secondes.

      conf/nginx.conf

      . . .
      client_max_body_size 4G;
      keepalive_timeout 5;
      . . .
      

      Le premier bloc location permet à Nginx d’accéder aux demandes de proxy vers les serveurs upstream django sur HTTP. Il préserve également les en-têtes HTTP du client qui capturent l’adresse IP d’origine, le protocole utilisé pour la connexion et l’hôte cible :

      conf/nginx.conf

      . . .
      location / {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://django;
      }
      . . .
      

      Pour en savoir plus sur ces directives, consultez Deploying Gunicorn et Module ngx_http_proxy_module à partir des docs Deploying

      Le bloc location final capture les demandes vers le chemin /well-known/acme-challenge/ utilisé par Certbot pour les défis HTTP-01 pour vérifier votre domaine avec Let’s Encrypt et fournir ou renouveler les certificats TLS. Pour plus d’informations sur le défi HTTP-01 utilisé par Certbot, consultez les Types de défi dans les docs Let’s Encrypt.

      conf/nginx.conf

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

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

      Vous pouvez maintenant utiliser ce fichier de configuration pour exécuter un conteneur Docker Nginx. Dans ce tutoriel, nous utiliserons l’image nginx:1.19.0, version 1.19.0 de l’image Docker officielle maintenue par Nginx.

      Lorsque nous exécutons le conteneur pour la première fois, Nginx lancera une erreur et échouera car nous n’avons pas encore fourni les certificats définis dans le fichier de configuration. Cependant, nous allons toujours exécuter la commande pour télécharger l’image Nginx localement et tester que tout le reste fonctionne correctement :

      docker run --rm --name nginx -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Ici, nous nommons le conteneur nginx et cartographions les ports hôtes 80 et 443 vers les ports conteneur respectifs. Le drapeau -v monte le fichier de configuration dans le conteneur Nginx à /etc/nginx/conf.d/nginx.conf, que l’image Nginx est préconfigurée pour charger. Il est monté en mode ro ou “read only”, de sorte que le conteneur ne peut pas modifier le fichier. Le répertoire racine web /var/www/html est également monté dans le conteneur. Enfin, nginx:1.19.0 demande à Docker de tirer et d’exécuter l’image nginx:1.19.0 depuis Dockerhub.

      Docker tirera et exécutera l’image, puis Nginx lancera une erreur lorsqu’il ne trouvera pas le certificat TLS configuré et la clé secrète. Dans la prochaine étape, nous allons les fournir à l’aide d’un client Certbot Dockerizé et de l’autorité de certification Let’s Encrypt.

      Étape 4 — Configuration de Cerbot et renouvellement du certificat Let’s Encrypt

      Certbot est un client Let’s Encrypt développé par la Electronic Frontier Foundation. Il fournit des certificats TLS gratuits depuis l’autorité de certification Let’s Encrypt qui permet aux navigateurs de vérifier l’identité de vos serveurs web. Comme Docker a été installé sur notre serveur proxy Nginx, nous utiliserons l’image Certbot Docker pour fournir et renouveler les certificats TLS.

      Commencez par vous assurer que vous disposez d’un enregistrement DNS A mappé à l’adresse IP publique du serveur proxy. Ensuite, sur votre serveur proxy, proposez une version de mise en scène des certificats à l’aide de l’image certbot Docker :

      docker run -it --rm -p 80:80 --name certbot 
               -v "/etc/letsencrypt:/etc/letsencrypt" 
               -v "/var/lib/letsencrypt:/var/lib/letsencrypt" 
               certbot/certbot certonly --standalone --staging -d your_domain.com
      

      Cette commande exécute l’image certbot Docker en mode interactif, et achemine le port 80 de l’hôte au port 80 du conteneur. Il crée et monte deux répertoires hôtes dans le conteneur : /etc/letsencrypt/ et /var/lib/letsencrypt/ certbot est exécuté en mode stand alone, sans Nginx, et utilisera les serveurs staging de Let’s Encrypt pour effectuer la validation du domaine.

      Lorsque vous y êtes invité, entrez votre adresse email et acceptez les conditions de service. Si la validation du domaine a réussi, vous devriez voir la sortie suivante :

      Output

      Obtaining a new certificate Performing the following challenges: http-01 challenge for stubb.dev Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain.com/privkey.pem Your cert will expire on 2020-09-15. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal.

      Vous pouvez inspecter le certificat à l’aide de cat :

      sudo cat /etc/letsencrypt/live/your_domain.com/fullchain.pem
      

      Une fois le certificat TLS fourni, nous pouvons tester la configuration Nginx assemblée à l’étape précédente :

      docker run --rm --name nginx -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /etc/letsencrypt:/etc/letsencrypt 
          -v /var/lib/letsencrypt:/var/lib/letsencrypt 
          -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      C’est la même commande exécutée à l’Étape 3, avec l’ajout des deux répertoires Let’s Encrypt récemment créés.

      Une fois que Nginx est opérationnel, naviguez jusqu’à http://your_domain.com. Vous pouvez recevoir un avertissement dans votre navigateur signalant que l’autorité de certification est invalide. C’est normal car nous avons fourni des certificats de mise en scène et non pas des certificats Let’s Encrypt. Vérifiez la barre d’URL de votre navigateur pour confirmer que votre requête HTTP a été redirigée vers HTTPS.

      Entrez CTRL+C dans votre terminal pour quitter Nginx et exécutez à nouveau le client certbot, cette fois en omettant le drapeau --staging flag :

      docker run -it --rm -p 80:80 --name certbot 
               -v "/etc/letsencrypt:/etc/letsencrypt" 
               -v "/var/lib/letsencrypt:/var/lib/letsencrypt" 
               certbot/certbot certonly --standalone -d your_domain.com
      

      Lorsque vous êtes invité à conserver le certificat existant ou à le renouveler et à le remplacer, tapez 2 pour le renouveler et ensuite ENTER (ENTRÉE) pour confirmer votre choix.

      Une fois le certificat de production TLS fourni, exécutez à nouveau le serveur Nginx :

      docker run --rm --name nginx -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /etc/letsencrypt:/etc/letsencrypt 
          -v /var/lib/letsencrypt:/var/lib/letsencrypt 
          -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Dans votre navigateur, naviguez vers http://your_domain.com. Dans la barre d’URL, vérifiez que la requête HTTP a été redirigée vers HTTPS. Comme l’application de sondage n’a pas de route configurée par défaut, vous devriez voir une erreur Django Page not found. Naviguez vers https://your_domain.com/polls et vous verrez l’interface standard de l’application de sondage :

      Interface des applications de sondage

      Vous avez maintenant fourni un certificat TLS de production à l’aide du client Certbot Docker, et vous effectuez un proxying inverse et un équilibrage de charge des requêtes externes vers les deux serveurs d’application Django.

      Les certificats Let’s Encrypt expirent tous les 90 jours. Pour vous assurer que votre certificat reste valide, vous devriez le renouveler régulièrement avant son expiration prévue. Avec Nginx en cours d’exécution, vous devriez utiliser le client Certbot en mode webroot au lieu d’un mode standalone. Cela signifie que Certbot effectuera la validation en créant un fichier dans le répertoire /var/www/html/.well-known/acme-challenge/ et les demandes de validation Let’s Encrypt vers ce chemin seront captées par la règle location définie dans la configuration Nginx à l’Étape 3. Certbot effectuera ensuite la rotation des certificats, et vous pouvez recharger Nginx afin qu’il utilise ce certificat qui vient d’être fourni.

      Il existe de multiples façons d’automatiser cette procédure et le renouvellement automatique des certificats TLS va au-delà de la portée de ce tutoriel. Pour effectuer un processus similaire à l’aide de l’utilitaire de planification cron, consultez l’Étape 6 de Comment sécuriser une application Node.js avec Nginx, Let’s Encrypt et Docker Compose.

      Dans votre terminal, entrez sur CTRL+C pour terminer le conteneur Nginx. Exécutez-le à nouveau en mode détaché en apposant le drapeau -d :

      docker run --rm --name nginx -d -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /etc/letsencrypt:/etc/letsencrypt 
          -v /var/lib/letsencrypt:/var/lib/letsencrypt 
        -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Avec Nginx en cours d’exécution en arrière-plan, utilisez la commande suivante pour effectuer un essai de la procédure de renouvellement du certificat :

      docker run -it --rm --name certbot 
          -v "/etc/letsencrypt:/etc/letsencrypt" 
        -v "/var/lib/letsencrypt:/var/lib/letsencrypt" 
        -v "/var/www/html:/var/www/html" 
        certbot/certbot renew --webroot -w /var/www/html --dry-run
      

      Nous utilisons le plugin --webroot, spécifions le chemin racine web, et utilisons le drapeau --dry-run pour vérifier que tout fonctionne correctement sans réellement effectuer le renouvellement du certificat.

      Si la simulation de renouvellement réussit, vous devriez voir la sortie suivante :

      Output

      Cert not due for renewal, but simulating renewal for dry run Plugins selected: Authenticator webroot, Installer None Renewing an existing certificate Performing the following challenges: http-01 challenge for your_domain.com Using the webroot path /var/www/html for all unmatched domains. Waiting for verification... Cleaning up challenges - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - new certificate deployed without reload, fullchain is /etc/letsencrypt/live/your_domain.com/fullchain.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** 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.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

      Dans un environnement de production, après avoir renouvelé les certificats, vous devez recharger Nginx pour que les modifications prennent effet. Pour recharger Nginx, exécutez la commande suivante :

      docker kill -s HUP nginx
      

      Cette commande enverra un signal Unix HUP au processus Nginx en cours d’exécution dans le conteneur Docker nginx. À la réception de ce signal, Nginx rechargera sa configuration et les certificats renouvelés.

      Une fois HTTPS activé, et tous les composants de cette architecture opérationnels, la dernière étape consiste à verrouiller la configuration en empêchant l’accès externe aux deux serveurs d’application backend ; toutes les requêtes HTTP devraient passer par le proxy Nginx.

      Étape 5 — Prévention de l’accès externe aux serveurs d’application Django

      Dans l’architecture décrite dans ce tutoriel, la terminaison SSL se produit au niveau du proxy Nginx. Cela signifie que Nginx décrypte la connexion SSL, et que les paquets sont acheminés vers les serveurs d’application Django non cryptés. Pour de nombreux cas d’utilisation, ce niveau de sécurité est suffisant. Pour les applications impliquant des données financières ou sanitaires, vous souhaiterez peut-être mettre en place le cryptage de bout en bout. Vous pouvez le faire en envoyant des paquets cryptés via le répartiteur de charge et en les décryptant sur les serveurs d’application, ou en les cryptant à niveau du proxy et en décryptant une fois de plus sur les serveurs d’application Django. Ces techniques vont au-delà de la portée de cet article, mais pour en savoir plus veuillez consulter le Cryptage de bout en bout.

      Le proxy Nginx agit comme une passerelle entre le trafic externe et le réseau interne. En théorie, aucun client externe ne doit avoir un accès direct aux serveurs d’application internes, et toutes les demandes doivent passer par le serveur Nginx. La remarque de l’Étape 1 décrit brièvement un problème ouvert avec Docker où Docker contourne les paramètres du pare-feu ufw par défaut et ouvre les ports à l’extérieur, ce qui peut se révéler dangereux. Pour répondre à cette préoccupation de sécurité, il est recommandé d’utiliser les pare-feu en cloud lors de l’utilisation de serveurs Docker. Pour obtenir plus d’informations sur la création de pare-feu en cloud avec DigitalOcean, consultez Comment créer des pare-feu. Vous pouvez également manipuler directement les iptables au lieu d’utiliser ufw. Pour en savoir plus sur l’utilisation d’iptables avec Docker, consultez Docker et iptables.

      Au cours de cette étape, nous allons modifier la configuration d’UFW pour bloquer l’accès externe aux ports hôtes ouverts par Docker. En exécutant Django sur les serveurs d’application, nous avons passé le drapeau -p 80:8000 à docker, qui achemine le port 80 de l’hôte au port de conteneur 8000. Cela a également ouvert le port 80 à des clients externes, ce que vous pouvez vérifier en visitant http://your_app_server_1_IP. Pour éviter un accès direct, nous allons modifier la configuration d’UFW à l’aide de la méthode décrite dans le référentiel GitHub ufw-docker.

      Commencez par vous connecter au premier serveur d’application Django. Ensuite, ouvrez le fichier /etc/ufw/after.rules avec des privilèges super-utilisateur, à l’aide de nano ou de votre éditeur préféré :

      sudo nano /etc/ufw/after.rules
      

      Entrez votre mot de passe lorsque vous y serez invité, et appuyez sur ENTER pour confirmer.

      Vous devriez voir les règles ufw suivantes :

      /etc/ufw/after.rules

      #
      # rules.input-after
      #
      # Rules that should be run after the ufw command line added rules. Custom
      # rules should be added to one of these chains:
      #   ufw-after-input
      #   ufw-after-output
      #   ufw-after-forward
      #
      
      # Don't delete these required lines, otherwise there will be errors
      *filter
      :ufw-after-input - [0:0]
      :ufw-after-output - [0:0]
      :ufw-after-forward - [0:0]
      # End required lines
      
      # don't log noisy services by default
      -A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input
      -A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input
      -A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input
      -A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input
      -A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input
      -A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input
      
      # don't log noisy broadcast
      -A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input
      
      # don't delete the 'COMMIT' line or these rules won't be processed
      COMMIT
      

      Faites défiler vers le bas, et collez dans le bloc suivant des règles de configuration UFW :

      /etc/ufw/after.rules

      . . .
      
      # BEGIN UFW AND DOCKER
      *filter
      :ufw-user-forward - [0:0]
      :DOCKER-USER - [0:0]
      -A DOCKER-USER -j RETURN -s 10.0.0.0/8
      -A DOCKER-USER -j RETURN -s 172.16.0.0/12
      -A DOCKER-USER -j RETURN -s 192.168.0.0/16
      
      -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
      
      -A DOCKER-USER -j ufw-user-forward
      
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
      
      -A DOCKER-USER -j RETURN
      COMMIT
      # END UFW AND DOCKER
      

      Ces règles limitent l’accès du public aux ports ouverts par Docker, et permettent un accès à partir des plages IP privées 10.0.0/8, 172.16.0.0/12 et 192.168.0.0/16. Si vous utilisez VPC avec DigitalOcean, alors les Droplets de votre réseau VPC aura accès au port ouvert sur l’interface réseau privée, mais les clients externes ne l’auront pas. Pour plus d’informations sur VPC, consultez la documentation officielle de VPC. Pour en savoir plus sur les règles appliquées dans ce snippet, consultez Comment ça marche ? du fichier README ufw-docker.

      Si vous n’utilisez pas VPC avec DigitalOcean et que vous avez entré les adresses IP publiques des serveurs d’application dans le bloc upstream de votre configuration Nginx, vous devrez modifier explicitement le pare-feu UFW pour autoriser le trafic depuis le serveur Nginx par le port 80 sur les serveurs d’application Django. Pour obtenir des conseils sur la création de règles allow avec le pare-feu UFW, consultez les Essentiels  d’UFW: Règles et commandes communes du pare-feu.

      Quand vous avez terminé de le modifier, enregistrez et fermez le fichier.

      Redémarrez ufw afin qu’il adopte la nouvelle configuration :

      sudo systemctl restart ufw
      

      Naviguez vers http://APP_SERVER_1_IP dans votre navigateur web pour vérifier que vous ne pouvez plus accéder au serveur d’application sur le port 80.

      Répétez ce processus sur le deuxième serveur d’application Django.

      Déconnectez-vous du premier serveur d’application ou ouvrez une autre fenêtre de terminal, et connectez-vous au deuxième serveur d’application Django. Ensuite, ouvrez le fichier /etc/ufw/after.rules avec des privilèges super-utilisateur, à l’aide de nano ou de votre éditeur préféré :

      sudo nano /etc/ufw/after.rules
      

      Entrez votre mot de passe lorsque vous y serez invité, et appuyez sur ENTER pour confirmer.

      Faites défiler vers le bas, et collez dans le bloc suivant des règles de configuration UFW :

      /etc/ufw/after.rules

      . . .
      
      # BEGIN UFW AND DOCKER
      *filter
      :ufw-user-forward - [0:0]
      :DOCKER-USER - [0:0]
      -A DOCKER-USER -j RETURN -s 10.0.0.0/8
      -A DOCKER-USER -j RETURN -s 172.16.0.0/12
      -A DOCKER-USER -j RETURN -s 192.168.0.0/16
      
      -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
      
      -A DOCKER-USER -j ufw-user-forward
      
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
      
      -A DOCKER-USER -j RETURN
      COMMIT
      # END UFW AND DOCKER
      

      Quand vous avez terminé de le modifier, enregistrez et fermez le fichier.

      Redémarrez ufw afin qu’il adopte la nouvelle configuration :

      sudo systemctl restart ufw
      

      Naviguez vers http://APP_SERVER_2_IP dans votre navigateur web pour vérifier que vous ne pouvez plus accéder au serveur d’application sur le port 80.

      Enfin, naviguez jusqu’à https://your_domain_here/polls pour confirmer que le proxy Nginx a toujours accès aux serveurs Django en amont. Vous devriez voir l’interface de ‘application de sondage.

      Conclusion

      Dans ce tutoriel, vous avez mis en place une application de sondage Django évolutive à l’aide de conteneurs Docker. Au fur et à mesure que votre trafic et la charge sur le système grandissent, vous pouvez faire évoluer chaque couche séparément : la couche proxy Nginx, la couche d’application backend Django et la couche de base de données PostgreSQL.

      Lorsque vous construisez un système distribué, vous devez souvent faire face à de multiples décisions de conception, et plusieurs architectures peuvent satisfaire votre cas d’utilisation. L’architecture décrite dans ce tutoriel est conçue comme un modèle flexible pour la conception d’applications évolutives avec Django et Docker.

      Vous pouvez vouloir contrôler le comportement de vos conteneurs lorsqu’ils rencontrent des erreurs, ou exécuter automatiquement les conteneurs lorsque votre système démarre. Pour ce faire, vous pouvez utiliser un gestionnaire de processus comme Systemd ou mettre en œuvre des politiques de redémarrage. Pour plus d’informations à ce propos, consultez la section Démarrer les conteneurs automatiquement dans la documentation Docker.

      Lorsque vous travaillez à l’échelle avec plusieurs hôtes exécutant la même image Docker, il peut être plus efficace d’automatiser les étapes à l’aide d’un outil de gestion de configuration comme Ansible ou Chef. Pour en savoir plus sur la gestion de la configuration, consultez Une Introduction à la gestion de la configuration et Configuration de serveur automatisée avec Ansible : un kit d’atelier DigitalOcean.

      Au lieu de construire la même image sur chaque hôte, vous pouvez également rationaliser le déploiement à l’aide d’un registre d’images comme Docker Hub, qui construit, stocke et distribue des images Docker à plusieurs serveurs de manière centralisée. En plus d’un registre d’images, un pipeline d’intégration et de déploiement continu peut vous aider à construire, tester et déployer des images sur vos serveurs d’application. Pour plus d’informations sur les CI/CD, veuillez consulter Une Introduction aux meilleures pratiques de CI/CD.



      Source link

      Comment installer une pile ERPNext sur Ubuntu 20.04


      L’auteur a choisi Software in the Public Interest pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      ERPNext est une suite de planification des ressources d’entreprise (ERP) qui tire parti de la puissance et de la flexibilité des technologies open-source. Elle excelle dans la gestion des processus opérationnels de base tels que la finance, les ventes, les ressources humaines, la fabrication, les achats, les services, les besoins du helpdesk, et plus encore. Parmi les avantages de la mise en œuvre d’un système comme ERPNext, on peut citer :

      • Une meilleure productivité en automatisant les processus commerciaux répétitifs
      • Une amélioration de l’efficacité informatique en partageant une base de données pour tous les départements de la société
      • Une meilleure prise de décisions grâce à une vision intégrale de la relation entre les unités commerciales

      ERPNext repose sur Frappe, un cadre d’application web full-stack écrit en Python qui tire pleinement parti de l’environnement d’exécution Node/JavaScript et utilise MariaDB comme backend de base de données. L’un des nombreux avantages des applications reposant sur Frappe, comme ERPNext, est l’utilitaire de ligne de commande bench. L’ILC bench permet aux administrateurs de gagner du temps en automatisant des tâches telles que l’installation, la mise à jour, la configuration et la gestion de plusieurs sites Frappe/ERPNext.

      Dans ce tutoriel, vous installerez et configurez une pile ERPNext sur un serveur tournant sous Ubuntu 20.04. Cela vous permettra de configurer votre pile pour divers environnements de développement ou de production en fonction de vos besoins, et cela vous préparera à construire une architecture plus complexe et tolérante aux défauts.

      Conditions préalables

      Note : Lorsque vous choisissez les spécifications de votre serveur, n’oubliez pas que les systèmes ERP sont gourmands en ressources. Ce guide préconise un serveur de 4 Go de RAM, ce qui est suffisant pour les cas d’utilisation de base, mais les exigences matérielles spécifiques peuvent varier en fonction du nombre d’utilisateurs et de la taille de votre entreprise.

      Étape 1 — Configuration du pare-feu

      Bien que la configuration d’un pare-feu pour le développement soit facultative, pour la production il s’agit d’une pratique de sécurité obligatoire.

      Vous devrez ouvrir les ports suivants sur votre serveur ERPNext :

      • 80/tcp et 443/tcp pour HTTP et HTTPS, respectivement
      • 3306/tcp pour la connexion à MariaDB (recommandé uniquement si vous avez besoin d’un accès à la base de données à distance)
      • 143/tcp et 25/tcp pour IMAP et STMP, respectivement
      • 22/tcp pour SSH (si vous n’avez pas encore activé OpenSSH dans vos paramètres UFW)
      • 8000/tcp pour tester votre plate-forme avant de la déployer en production

      Pour ouvrir plusieurs ports à la fois, vous pouvez utiliser la commande suivante :

      • sudo ufw allow 22,25,143,80,443,3306,8000/tcp

      Vous pouvez également autoriser des connexions à partir d’adresses IP spécifiques sur des ports spécifiques en utilisant cette commande :

      • sudo ufw allow from server_IP to any port port_number

      Après avoir ouvert tous les ports nécessaires, activez le pare-feu :

      Confirmez maintenant l’état de votre pare-feu :

      UFW fournira une liste des règles que vous avez autorisées. Assurez-vous que les ports nécessaires d’ERPNext sont ouverts :

      Output

      Status: active To Action From -- ------ ---- 22,25,80,143,443,3306,8000/tcp ALLOW Anywhere 22,25,80,143,443,3306,8000/tcp (v6) ALLOW Anywhere (v6)

      Pour plus d’informations sur la configuration d’UFW, consultez notre guide Comment configurer un pare-feu avec UFW sur Ubuntu 20.04.

      La mise en place d’un pare-feu approprié est la première des deux étapes préliminaires. Vous allez maintenant configurer le mappage du clavier et l’encodage des caractères sur votre serveur.

      Étape 2 — Configuration des sites

      Il est fortement recommandé de configurer le mappage du clavier pour la console ainsi que la langue et l’encodage des caractères sur votre hôte. Ceci est nécessaire pour éviter les problèmes éventuels lors du processus d’installation d’ERPNext 12. Remarquez que cette configuration n’a rien à voir avec la langue de l’interface utilisateur sur votre plateforme ERPNext actuelle, mais avec la configuration locale du système.

      Tout d’abord, mettez à jour votre serveur :

      Configurez maintenant le keymap, la langue et l’encodage des caractères :

      • sudo localectl set-keymap us && sudo localectl set-locale LANG=en_US.utf8

      L’utilitaire localectl est utilisé par Ubuntu 20.04 et d’autres distributions Linux pour contrôler et modifier les paramètres locaux et la disposition du clavier à l’échelle du système, avant que l’utilisateur ne se connecte, ce qui est exactement ce dont ERPNext 12 a besoin.

      Vous devrez également ajouter les lignes suivantes à votre fichier /etc/environment. Utilisez nano ou votre éditeur de texte préféré pour ouvrir le fichier :

      • sudo nano /etc/environment

      Maintenant ajoutez le contenu suivant :

      /etc/environment

      LC_ALL=en_US.UTF-8
      LC_CTYPE=en_US.UTF-8
      LANG=en_US.UTF-8
      

      Enregistrez et fermez le fichier.

      Redémarrez votre serveur pour appliquer tous les changements :

      Laissez à votre serveur quelques minutes pour redémarrer, puis utilisez ssh pour réintroduire votre instance. Vous êtes maintenant prêt à installer votre base de données.

      Étape 3 — Installation de MariaDB

      Vous allez maintenant ajouter MariaDB à la pile de votre serveur. ERPNext 12 requiert MariaDB 10.2+ pour fonctionner correctement. Comme Ubuntu 20.04 inclut MariaDB 10.3 dans ses référentiels officiels, vous pouvez installer cette version en utilisant la commande apt :

      • sudo apt install mariadb-server

      Si vous préférez une version plus récente de MariaDB, vous pouvez suivre l’Étape 3 de notre guide Comment installer une pile ERPNext sur Ubuntu 18.04. Cela vous guidera à travers l’assistant du référentiel en ligne de MariaDB, qui vous aidera à installer la version la plus récente : MariaDB 10.5.

      Après avoir installé mariadb-server, installez les packages suivants :

      • sudo apt install python3-mysqldb libmysqlclient-dev

      ERPNext 12 est une application Python : elle requiert donc la bibliothèque python3-mysqldb pour la gestion de la base de données. libmysqlclient-dev est nécessaire pour accéder à certaines fonctionnalités de développeur MariaDB.

      Ensuite, ajoutez une couche de sécurité supplémentaire au serveur MariaDB, en exécutant le script mysql_secure_installation :

      • sudo mysql_secure_installation

      Le script mysql_secure_installation vous posera plusieurs questions :

      • La première invite vous demandera le mot de passe root, mais comme aucun de mot de passe n’a été configuré, appuyez sur ENTER.
      • Ensuite, lorsqu’il vous sera demandé de modifier le mot de passe root de MariaDB, répondez N. L’utilisation du mot de passe par défaut avec l’authentification Unix est la configuration recommandée pour les systèmes basés sur Ubuntu, car le compte root est étroitement lié aux tâches de maintenance automatisées du système.
      • Les questions restantes concernent la suppression de l’utilisateur anonyme de la base de données, la restriction du compte root pour vous connecter à distance sur localhost, la suppression de la base de données de test et le rechargement des tables de privilèges. Vous pouvez répondre Y à toutes ces questions en toute sécurité.

      Après avoir terminé le script mysql_secure_installation, MariaDB commencera à fonctionner en utilisant sa configuration par défaut. L’installation standard ERPNext utilise le root user de MariaDB, pour toutes les opérations de la base de données. Bien que cette approche soit pratique sur les configurations de serveur unique, elle n’est pas considérée comme une bonne pratique en matière de sécurité. Par conséquent, dans la section suivante, vous apprendrez à éviter ce problème en créant un nouvel utilisateur avec des privilèges spéciaux.

      Création d’un Super utilisateur admin de MariaDB

      ERPNext prévoit d’utiliser le root user de MariaDB pour gérer les connexions aux bases de données, mais ce n’est pas toujours idéal. Pour contourner cette limitation et laisser un non-root user gérer MariaDB, vous allez maintenant créer manuellement une base de données portant le nom de l’utilisateur. Ensuite, vous serez en mesure d’attribuer des privilèges spéciaux au nouvel utilisateur pour conduire les opérations de la base de données d’ERPNext.

      Ouvrez l’invite MariaDB :

      Créez maintenant une nouvelle base de données nommée d’après l’utilisateur que vous souhaitez affecter aux connexions MariaDB. Ce tutoriel utilisera sammy, mais vous pouvez choisir un nom différent :

      Confirmez que la base de données a été créée en utilisant cette instruction SQL :

      Vous obtiendrez une sortie semblable à ceci :

      Output

      +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sammy | +--------------------+

      Créez maintenant l’utilisateur MariaDB sammy avec des privilèges similaires à root, puis donnez à l’utilisateur un mot de passe fort de votre choix. Conservez le mot de passe dans un endroit sûr, vous en aurez besoin plus tard :

      • GRANT ALL PRIVILEGES ON *.* TO 'sammy'@'%' IDENTIFIED BY 'mariadb_password' WITH GRANT OPTION;

      Confirmez maintenant la création de l’utilisateur et les privilèges du nouvel utilisateur :

      • SELECT host, user, Super_priv FROM mysql.user;

      Vous verrez un résultat similaire à ce qui suit :

      Output

      +-----------+-------+------------+ | Host | User | Super_priv | +-----------+-------+------------+ | localhost | root | Y | | localhost | mysql | Y | | % | sammy| Y | +-----------+-------+------------+ 3 rows in set (0.001 sec)

      Maintenant videz les privilèges pour appliquer tous les changements :

      Une fois que vous avez terminé, quittez la session :

      Maintenant que vous avez créé un utilisateur de la base de données, il ne vous reste plus qu’à régler MariaDB pour vous assurer le fonctionnement correct d’ERPNext 12. Heureusement, l’équipe ERPNext fournit un excellent modèle de configuration que vous utiliserez comme point de départ pour votre implémentation. Dans la section suivante, vous apprendrez à configurer correctement la base de données MariaDB en utilisant ce modèle.

      Étape 4 — Configuration de MariaDB pour ERPNext

      Une fois MariaDB installé et sécurisé, il est temps de le mettre au point pour les connexions ERPNext.

      Tout d’abord, arrêtez mariadb.service :

      • sudo systemctl stop mariadb

      Utilisez maintenant nano ou votre éditeur de texte préféré pour créer un fichier de configuration MariaDB appelé mariadb.cnf :

      • sudo nano /etc/mysql/mariadb.conf.d/mariadb.cnf

      Ensuite, ajoutez le modèle de configuration officiel d’ERPNext :

      /etc/mysql/mariadb.conf.d/mariadb.cnf

      [mysqld]
      
      # GENERAL #
      user                           = mysql
      default-storage-engine         = InnoDB
      socket                         = /var/lib/mysql/mysql.sock
      pid-file                       = /var/lib/mysql/mysql.pid
      
      # MyISAM #
      key-buffer-size                = 32M
      myisam-recover                 = FORCE,BACKUP
      
      # SAFETY #
      max-allowed-packet             = 256M
      max-connect-errors             = 1000000
      innodb                         = FORCE
      
      # DATA STORAGE #
      datadir                        = /var/lib/mysql/
      
      # BINARY LOGGING #
      log-bin                        = /var/lib/mysql/mysql-bin
      expire-logs-days               = 14
      sync-binlog                    = 1
      
      # REPLICATION #
      server-id                      = 1
      
      # CACHES AND LIMITS #
      tmp-table-size                 = 32M
      max-heap-table-size            = 32M
      query-cache-type               = 0
      query-cache-size               = 0
      max-connections                = 500
      thread-cache-size              = 50
      open-files-limit               = 65535
      table-definition-cache         = 4096
      table-open-cache               = 10240
      
      # INNODB #
      innodb-flush-method            = O_DIRECT
      innodb-log-files-in-group      = 2
      innodb-log-file-size           = 512M
      innodb-flush-log-at-trx-commit = 1
      innodb-file-per-table          = 1
      innodb-buffer-pool-size        = 5462M
      innodb-file-format             = barracuda
      innodb-large-prefix            = 1
      collation-server               = utf8mb4_unicode_ci
      character-set-server           = utf8mb4
      character-set-client-handshake = FALSE
      max_allowed_packet             = 256M
      
      # LOGGING #
      log-error                      = /var/lib/mysql/mysql-error.log
      log-queries-not-using-indexes  = 0
      slow-query-log                 = 1
      slow-query-log-file            = /var/lib/mysql/mysql-slow.log
      
      # CONNECTIONS #
      
      pid-file        = /var/run/mysqld/mysqld.pid
      socket          = /var/run/mysqld/mysqld.sock
      bind-address    = 0.0.0.0
      
      [mysql]
      default-character-set = utf8mb4
      
      [mysqldump]
      max_allowed_packet=256M
      

      Enregistrez et fermez le fichier. Pour obtenir des informations plus détaillées sur ces configurations, consultez ce fichier modèle sur le référentiel Github d’ERPNext. C’est un point de départ utile pour explorer ces options.

      Le fichier de configuration,/etc/mysql/mariadb.conf.d/mariadb.cnf, complète et remplace également quelques valeurs incluses dans la configuration par défaut de MariaDB située dans /etc/mysql/my.cnf. Ce fichier vous donne un modèle de conservation qui améliore considérablement les performances de la base de données pour ERPNext. N’oubliez pas toutefois que si ce modèle est un excellent point de départ, rien ne vous empêche d’améliorer encore plus les performances de MariaDB en ajustant ces paramètres à vos besoins.

      Test de la connexion MariaDB

      Comme ERPNext dépend de la connexion à la base de données pour presque toutes ses opérations internes, il est bon de tester la connexion avant de continuer.

      Démarrez mariadb.service :

      • sudo systemctl start mariadb

      Pour tester la connexion, vous pouvez utiliser la commande suivante. N’oubliez pas de remplacer sammy et mariadb_password par vos identifiants :

      • mysql --user sammy --password mariadb_password --host=localhost --protocol=tcp --port=3306 test

      Vous verrez un résultat montrant le contenu de l’aide de base de MariaDB et plusieurs paramètres. Cela signifie que votre connexion a réussi :

      Output

      mysql Ver 15.1 Distrib 10.4.13-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2 Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Usage: mysql [OPTIONS] [database] Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf ... --ssl-verify-server-cert Verify server's "Common Name" in its cert against hostname used when connecting. This option is disabled by default. -t, --table Output in table format. --tee=name Append everything into outfile. See interactive help (h) also. Does not work in batch mode. Disable with --disable-tee. This option is disabled by default. -u, --user=name User for login if not current user. -U, --safe-updates Only allow UPDATE and DELETE that uses keys. -U, --i-am-a-dummy Synonym for option --safe-updates, -U. -v, --verbose Write more. (-v -v -v gives the table output format). ... max-join-size 1000000 secure-auth FALSE show-warnings FALSE plugin-dir (No default value) default-auth (No default value) binary-mode FALSE connect-expired-password FALSE

      Si vous devez apporter des ajustements aux paramètres de MariaDB ou corriger des erreurs, n’oubliez pas de recharger le service en utilisant la commande suivante :

      • sudo systemctl restart mariadb

      Une fois que vous avez terminé, activez MariaDB :

      • sudo systemctl enable mariadb

      Maintenant que vous avez testé la connexion à la base de données, vous pouvez continuer à installer votre application ERPNext.

      Étape 5 — Configuration d’ERPNext 12

      Maintenant que le backend de votre base de données est prêt, vous pouvez continuer à configurer votre application web ERPNext. Dans cette section, vous apprendrez à installer et configurer tous les composants requis par ERPNext 12, puis à installer l’application elle-même.

      Commencez par préparer le serveur avec tous les paquets système requis par ERPNext 12. Installez les dépendances dans tout le système en utilisant la commande suivante :

      • sudo DEBIAN_FRONTEND=noninteractive apt install -y curl build-essential python3-testresources python3-setuptools python3-dev libffi-dev python3-pip libcurl4 dnsmasq fontconfig git htop libcrypto++-dev libfreetype6-dev liblcms2-dev libwebp-dev libxext6 libxrender1 libxslt1-dev libxslt1.1 libffi-dev ntpdate postfix python3-dev python-tk screen vim xfonts-75dpi xfonts-base zlib1g-dev apt-transport-https libsasl2-dev libldap2-dev libcups2-dev pv libjpeg8-dev libtiff5-dev tcl8.6-dev tk8.6-dev libdate-manip-perl logwatch

      La variable DEBIAN_FRONTEND=noninteractive a été transmise à la commande d’installation afin d’éviter les invites Postfix. Pour obtenir des informations détaillées sur la configuration de Postfix, lisez notre guide Comment installer et configurer Postfix sur Ubuntu 20.04

      Ensuite, mettez à jour pip3, qui est le gestionnaire de paquets standard de Python, puis installez les dernières versions de trois modules Python supplémentaires :

      • sudo -H python3 -m pip install --upgrade setuptools cryptography psutil

      setuptools facilite l’installation et la mise à jour des paquets Python, cryptography ajoute des capacités de cryptage à votre pile et psutil aide à la surveillance du système. Maintenant que vous avez installé toutes les dépendances générales nécessaires, vous allez installer tous les services et les bibliothèques nécessaires à ERPNext 12.

      Configuration de Node.js et Yarn

      ERPNext 12 peut fonctionner avec la version 8+ de l’environnement serveur Node.js. Au moment de la rédaction de ce texte, le script officiel easy_install d’ERPNext utilise Node 8. Mais du point de vue de la sécurité, il est conseillé d’installer une version plus récente, car Node 8 a atteint sa fin de vie (EOL) en 2020 et ne bénéficiera donc plus de correctifs de sécurité. Au moment de la rédaction de ce texte, Ubuntu 20.04 contient la version 10.19 de Node.js. Bien que cette version soit toujours maintenue, pour des raisons similaires (EOL dans moins d’un an), il est fortement conseillé de l’éviter. Pour les besoins de ce guide, Node.js version 12 LTS sera installé avec les gestionnaires de paquets npm et yarn correspondants. Veuillez noter que le framework Frappe utilise yarn pour installer les dépendances. Si vous décidez d’utiliser une autre méthode d’installation, vérifiez que la version 1.12+ de yarn fonctionne sur votre système.

      Ajoutez le référentiel NodeSource à votre système :

      • curl -sL https://deb.nodesource.com/setup_12.x -o nodesource_setup.sh

      Vous pouvez maintenant inspecter le contenu du script téléchargé :

      • sudo nano nodesurce_setup.sh

      Lorsque vous êtes satisfait du contenu du script, vous pouvez exécuter le script :

      • sudo bash nodesource_setup.sh

      Ce script mettra à jour automatiquement la liste apt. Vous pouvez maintenant installer nodejs sur votre serveur :

      Ensuite, installez yarn en utilisant le gestionnaire de paquets npm :

      Maintenant que vous avez installé Node, vous pouvez continuer à configurer wkhtmltopdf pour votre plate-forme.

      ERPNext utilise l’outil open source wkhtmltopdf pour convertir le contenu HTML en PDF, en utilisant le moteur de rendu Qt WebKit. Cette fonction est principalement utilisée pour l’impression de factures, de devis et d’autres rapports. Dans le cas d’ERPNext 12, une version spécifique de wkhtmltopdf est requise, 0.12.5 avec Qt patché.

      Pour installer wkhtmltopdf, commencez par passer à un répertoire approprié pour télécharger le paquet, dans ce cas /tmp :

      Téléchargez la version wkhtmltopdf appropriée et le paquet pour Ubuntu 20.04 depuis la page du projet :

      • wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.bionic_amd64.deb

      Installez maintenant le paquet en utilisant l’outil dpkg :

      • sudo dpkg -i wkhtmltox_0.12.5-1.bionic_amd64.deb

      Ensuite, copiez tous les exécutables pertinents dans votre répertoire /usr/bin/ :

      • sudo cp /usr/local/bin/wkhtmlto* /usr/bin/

      Une fois les fichiers en place, modifiez leurs autorisations pour les rendre exécutables :

      • sudo chmod a+x /usr/bin/wk*

      Maintenant que wkhtmltopdf est correctement installé, nous ajouterons Redis à notre pile de base de données.

      Installation de Redis

      ERPNext 12 utilise Redis pour améliorer les performances de MariaDB. Plus précisément, Redis aide à la mise en cache.

      Tout d’abord, installez Redis depuis le référentiel officiel Ubuntu 20.04 :

      • sudo apt install redis-server

      Ensuite, activez Redis au démarrage :

      • sudo systemctl enable redis-server

      Maintenant que vous avez ajouté Redis à votre pile, prenons un moment pour résumer ce que vous avez accompli jusqu’à présent. Jusqu’à ce stade, vous avez installé tous les principaux composants requis par ERPNext 12, qui comprennent :

      • Un backend de base de données MariaDB
      • L’environnement serveur JavaScript Node.js
      • Le gestionnaire de paquets Yarn
      • Un cache de la base de donnée de Redis
      • Le générateur de documents PDF wkhtmltopdf

      Que vous installiez le système ERP pour le développement ou pour la production, vous êtes maintenant prêt pour la prochaine étape, qui consiste à installer le framework full-stack Frappe et l’application web ERPNext 12 actuelle.

      Étape 6 — Configuration de l’ILC Bench de Frappe

      Maintenant que vous avez mis en place toutes les exigences de pile d’ERPNext, vous pouvez exploiter la flexibilité de l’utilitaire de ligne de commande bench de Frappe. L’ILC bench a été conçue dans le but d’aider les utilisateurs dans le processus d’installation, de mise en place et de gestion d’applications comme ERPNext, qui reposent sur le Framework Frappe. Dans les sections suivantes, vous allez installer l’ILC bench et l’utiliser ensuite pour terminer le processus de configuration d’ERPNext 12.

      Assurez-vous que l’utilisateur de Frappe (dans ce cas sammy) dispose des droits appropriés sur son répertoire home :

      • sudo chown sammy -R /home/sammy

      Maintenant, clonez le référentiel frappe/bench vers votre répertoire de base. N’oubliez pas de remplacer sammy par votre nom d’utilisateur système :

      • git clone https://github.com/frappe/bench /home/sammy/.bench --depth 1 --branch master

      Installez l’ILC bench :

      • sudo pip3 install -e /home/sammy/.bench

      Ce guide suppose que vous installez ERPNext 12 pour des scénarios de test/production et que vous utilisez donc la branche master. Mais si votre intention est de développer des applications ou des modules ERPNext personnalisés, la branche develop pourrait être préférable. Dans les deux cas, vous êtes maintenant prêt à installer le Framework de Frappe. Ce sera la dernière étape avant d’installer ERPNext lui-même.

      Configuration de l’environnement du framework de Frappe

      Dans cette section, vous allez créer un environnement Frappe en utilisant l’ILC bench.

      Pendant l’installation de Frappe, vous pouvez dépasser la limite de surveillance des fichier d’Ubuntu, qui par défaut est fixée à 8192. Pour éviter ce problème, définissez une limite supérieure en utilisant la commande suivante :

      • echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

      La commande tee ajoutera le contenu de votre commande echo au fichier appelé tout en imprimant la sortie sur votre console.

      Ensuite, initialisez Frappe framework 12. Remplacez Sammy par votre nom d’utilisateur système :

      • bench init /home/sammy/frappe-bench --frappe-path https://github.com/frappe/frappe --frappe-branch version-12 --python python3

      Au cours de l’exécution, vous pouvez voir une erreur concernant votre chemin d’accès, ainsi que plusieurs avertissements. Laissez le processus se poursuivre jusqu’à la fin. Une fois terminé, vous verrez un résultat similaire à celui qui suit, indiquant que votre environnement a été créé avec succès :

      Output

      ... Done in 82.23s. INFO:bench.utils:setting up backups no crontab for sammy SUCCESS: Bench /home/sammy/frappe-bench initialized

      Note : le processus bench init pourrait s’arrêter si une erreur spawn ENOMEM était rencontrée. Cette erreur se produit lorsque votre système manque de mémoire. Vous devez corriger le problème avant de continuer, soit en installant plus de mémoire physique, soit en attribuant l’espace SWAP.

      Examinons de plus près la commande utilisée pour créer l’environnement :

      • /home/sammy/frappe-bench est le chemin où le framework Frappe, les sites web et les applications connexes seront installés. Un nouveau répertoire, appelé frappe-bench dans cet exemple, sera créé pour accueillir tous les fichiers nécessaires.
      • --frappe-path pointe vers le référentiel de Frappe, qui dans ce cas est le référentiel officiel de Github.
      • --frappe-branch est la version Frappe à installer. Comme vous souhaitez installer ERPNext 12, la version choisie est Frappe 12.
      • --python est la version Python qui sera utilisée. ERPNext 12 requiert Python 3.6+. Les versions antérieures, cependant, utilisent toujours Python 2.7.

      Pour plus d’informations sur les commandes ILC bench, veuillez vous référer à la fiche d’aide des commandes de Bench.

      La flexibilité offerte par le framework Frappe va bien au-delà de l’utilisation d’environnements isolés. Vous pouvez également créer différents sites web et y installer des applications.

      Étape 7 — Configuration de l’application web ERPNext 12

      Dans cette section, vous allez configurer un site reposant sur Frappe, puis installer l’application ERPNext 12 sur celui-ci.

      Passez dans le répertoire où Frappe a été initialisé.

      • cd /home/sammy/frappe-bench

      Avant de continuer, vous devrez installer des versions spécifiques des bibliothèques Python numpy et pandas dans l’environnement virtuel de Frappe. Installez ces paquets en utilisant la commande suivante :

      • ./env/bin/pip install numpy==1.18.5 && ./env/bin/pip install pandas==0.24.2

      À ce stade, l’installation pourrait s’arrêter pendant environ 10 à 20 minutes tout en affichant ce message :

      Output

      ... Building wheel for pandas (setup.py) ... -

      Cela est dû à un bug lié à pandas et Ubuntu 20.04, qui, au moment où nous écrivons ces lignes, est encore assez récent. Néanmoins les paquets s’installeront, et une fois que cela sera terminé, vous verrez un résultat comme celui-ci :

      Output

      ... Successfully built pandas Installing collected packages: pandas Successfully installed pandas-0.24.2

      Vous pouvez maintenant continuer l’installation. Téléchargez ERPNext 12 depuis son référentiel en utilisant l’ILC bench :

      • bench get-app erpnext https://github.com/frappe/erpnext --branch version-12

      Ensuite, créez le nouveau site, en remplaçant your_domain par le domaine que vous avez associé à l’IP de ce serveur :

      • bench new-site your_domain --admin-password 'erpnext_admin_password' --mariadb-root-username sammy --mariadb-root-password 'mariadb_password'

      Prenons un moment pour examiner les options utilisées dans la commande ci-dessus :

      • bench new-site crée un nouveau site reposant sur le framework Frappe.
      • your_domain est le nom du nouveau site. Assurez-vous que le DNS de votre domaine a un enregistrement A pointant vers l’IP de votre serveur.
      • erpnext_admin_passwordest le mot de passe souhaité pour l’utilisateur Administrator d’ERPNext. Conservez ce mot de passe dans un endroit sûr, vous en aurez besoin sous peu.
      • mariadb_password est le mot de passe que vous avez créé au début du guide de l’utilisateur sammy de MariaDB.

      Ensuite, installez l’application ERPNext sur le site :

      • bench --site your_domain install-app erpnext

      Une fois l’installation terminée, vous disposerez d’une application ERPNext 12 fonctionnelle. Maintenant, testons-la à l’aide d’une commande bench :

      La commande ci-dessus lancera une console de surveillance en temps réel vous montrant divers messages concernant le serveur web et d’autres services. Ouvrez un navigateur web et naviguez vers localhost:8000 (pour les installations locales) ou your_domain:8000 (si vous utilisez un serveur distant). Vous verrez l’écran de connexion ERPNext (nous procéderons à la connexion et à la configuration dans une étape ultérieure, une fois que notre site sera prêt pour la production).

      Après avoir consulté votre déploiement de test, retournez à votre terminal et appuyez sur CTRL+C. Cela arrêtera ERPNext et permettra de quitter la console de surveillance.

      Si votre objectif principal est de créer des modules ou de modifier ERPNext 12, vous pouvez alors vous arrêter à ce stade. Aucun autre composant n’est nécessaire pour le développement. Cependant, si vous avez besoin d’un système prêt pour la production qui ne requiert pas d’initialisation manuelle, vous devrez alors installer et configurer quelques composants supplémentaires. C’est votre prochaine étape.

      Étape 8 — Configuration d’ERPNext 12 pour la production

      Bien que votre application ERPNext 12 soit prête, le système dans son ensemble n’est pas encore prêt pour la production. Pour garantir la fiabilité et la sécurité d’ERPNext, vous devrez activer quelques services supplémentaires :

      • Fail2ban fournit une couche supplémentaire de protection contre les tentatives de recours abusif des utilisateurs et des bots malveillants.
      • Nginx fonctionne principalement comme un proxy web, redirigeant tout le trafic depuis le port 8000 vers le port 80 (HTTP) ou le port 443 (HTTPS)
      • Supervisor veille à ce que les processus clés d’ERPNext soient constamment opérationnels, en les redémarrant au besoin.

      Jusqu’à ce stade, vous avez installé et configuré manuellement ERPNext 12, ce qui vous a permis de personnaliser le processus pour qu’il corresponde à n’importe quel cas d’utilisation particulier. Néanmoins, pour le reste de la configuration de la production, vous pouvez tirer parti de la commodité de l’ILC bench, afin d’automatiser l’installation et la configuration de ces services restants.

      Assurez-vous que vous êtes bien dans le répertoire de travail de Frappe :

      • cd /home/sammy/frappe-bench

      Maintenant, utilisez la commande suivante pour terminer la configuration d’ERPNext 12 pour la production :

      • sudo bench setup production sammy --yes

      La commande ci-dessus installera et configurera aNginx, Supervisor, et Fail2Ban, et définira sammy comme propriétaire de l’environnement de production.

      Les fichiers de configuration créés par la commande bench  sont les suivants :

      • Deux fichiers de configuration Nginx situés dans /etc/nginx/nginx.conf et /etc/nginx/conf.d/frappe-bench.conf
      • Un proxy jail Fail2Ban situé dans /etc/fail2ban/jail.d/nginx-proxy.conf et un filtre situé dans /etc/fail2ban/filter.d/nginx-proxy.conf

      Ces configurations par défaut suffiront pour ce tutoriel, mais n’hésitez pas à explorer et ajuster ces fichiers pour qu’ils correspondent à vos besoins. Vous pouvez arrêter tous les services en exécutant :

      • sudo supervisorctl stop all

      Et ensuite, une fois que vous êtes prêt, vous pouvez redémarrer vos services :

      • sudo supervisorctl start all

      Maintenant vous êtes prêt pour tester votre installation.

      Test de votre installation ERPNext 12

      Tout d’abord, vérifiez que les services de production clés sont en cours d’exécution. Utilisez la commande systemctl suivante, puis acheminez-la à grep :

      • systemctl list-unit-files | grep 'fail2ban|nginx|supervisor'

      Vous verrez un résultat similaire à ce qui suit :

      Output

      fail2ban.service enabled nginx.service enabled supervisor.service enabled

      Après avoir confirmé que tout fonctionne comme prévu, vous pouvez tester ERPNext 12 en direct sur votre serveur. Ouvrez votre navigateur favori et naviguez sur your_domain, ou là où vous hébergez votre application ERPNext 12.

      Après quelques secondes, vous devriez voir l’écran de connexion d’ERPNext 12. Utilisez Administrator pour le nom d’utilisateur (email) et erpnext_admin_password que vous avez créé précédemment pour le mot de passe.

      Écran de connexion d'ERPNext

      Dans l’écran suivant, vous verrez un menu déroulant où vous pouvez sélectionner la langue de l’interface utilisateur pour l’application :

      Sélection de la langue

      Après la sélection de la langue, ERPNext vous demandera d’entrer votre pays, votre fuseau horaire et votre devise :

      Sélectionnez votre région

      Une fois que vous aurez complété les informations sur votre région, vous pourrez créer votre premier utilisateur ERPNext. Les informations que vous fournissez seront utilisées comme identifiants de connexion de l’utilisateur.

      Premier utilisateur ERPNext

      Dans l’écran suivant, vous serez questionné sur ce qu’ERPNext appelle Domains. Si vous n’êtes pas sûr de savoir quel est votre domaine, sélectionnez Distribution et cliquez sur le bouton Next.

      Sélectionnez vos domaines

      Ensuite, vous devrez fournir un nom de société et une abréviation.

      Nom de la société

      Dans le dernier écran, ERPNext vous demandera d’indiquer l’activité de votre société, le nom de sa banque, le type de plan comptable et la période de l’exercice. Vous pourrez entrer des banques supplémentaires plus tard. Pour l’instant, remplissez tous les champs comme vous le souhaitez, puis cliquez sur le bouton Complete Setup.

      Informations financières

      Ensuite, vous verrez un barre de progression.

      Configuration d'ERPNext

      Une fois le processus de configuration terminé, le tableau de bord principal d’ERPNext 12 apparaît.

      Tableau de bord d'ERPNext 12

      Vous avez maintenant entièrement installé et configuré une application ERPNext 12.

      Conclusion

      Maintenant que vous avez correctement installé votre application ERPNext 12, vous pouvez commencer à mettre en œuvre le système pour vos besoins commerciaux. Un bon point de départ consiste à cliquer sur le bouton Getting Started sur le tableau de bord d’ERPNext. ERPNext vous aidera alors à configurer la plate-forme pour tous vos besoins commerciaux et de commerce électronique.

      Mise en route

      Vous pouvez également souhaiter améliorer la vitesse d’ERPNext. Si c’est le cas, vous pouvez lire les informations sur le réglage de performance ERPNext, qui vous guideront sur les meilleures pratiques et sur la manière de résoudre les problèmes liés aux performances.



      Source link

      Comment mettre en place une application Node.js pour la production sur Ubuntu 20.04


      Introduction

      Node.js est un environnement d’exécution JavaScript open-source pour la création d’applications côté serveur et de réseau. La plate-forme fonctionne sous Linux, macOS, FreeBSD et Windows. Bien que vous puissiez exécuter les applications Node.js en ligne de commande, ce tutoriel se concentre sur leur exécution en tant que service. Cela signifie qu’ils redémarreront au redémarrage ou en cas d’échec et qu’ils peuvent être utilisés en toute sécurité dans un environnement de production.

      Dans ce tutoriel, vous allez mettre en place un environnement Node.js prêt pour la production sur un seul serveur Ubuntu 20.04. Ce serveur exécutera une application Node.js gérée par PM2, et fournira aux utilisateurs un accès sécurisé à l’application via un proxy inverse Nginx. Le serveur Nginx offrira le HTTPS en utilisant un certificat gratuit fourni par Let’s Encrypt. 

      Conditions préalables

      Ce guide suppose que vous disposez des éléments suivants :

      Lorsque vous aurez rempli les conditions préalables, vous disposerez d’un serveur desservant la page par défaut de votre domaine à l’adresse https://example.com/. 

      Étape 1 — Installation de Node.js

      Commençons par installer la dernière version LTS de Node.js, en utilisant les archives des packages NodeSource.

      Tout d’abord, installez le NodeSource PPA afin d’avoir accès à son contenu. Assurez-vous que vous êtes dans votre répertoire d’origine et utilisez curl pour récupérer le script d’installation de la version LTS la plus récente de Node.js dans ses archives.

      • cd ~
      • curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh

      Vous pouvez inspecter le contenu de ce script avec nano ou votre éditeur de texte préféré :

      Lorsque vous avez fini d’inspecter le script, lancez le sous sudo: 

      • sudo bash nodesource_setup.sh

      Le PPA sera ajouté à votre configuration et le cache local de votre package sera automatiquement mis à jour. Après avoir exécuté le script d’installation à partir de Nodesource, vous pouvez installer le paquet Node.js :

      Pour vérifier quelle version de Node.js vous avez installée après ces premières étapes, tapez :

      Output

      v14.4.0

      Note : Lors de l’installation à partir du PPA NodeSource, l’exécutable Node.js est appelé nodejs, plutôt que node.

      Le paquet nodejs contient le binaire nodejs ainsi que npm, un gestionnaire de packages pour les modules Node, de sorte que vous n’avez pas besoin d’installer npm séparément.

      npm utilise un fichier de configuration dans votre répertoire de base pour suivre les mises à jour. Il sera créé la première fois que vous utiliserez npm. Exécutez cette commande pour vérifier que npm est installé et pour créer le fichier de configuration :

      Output

      6.14.5

      Pour que certains packages npm fonctionnent (par exemple, ceux qui nécessitent la compilation du code source), vous devrez installer le package build-essential :

      • sudo apt install build-essential

      Vous disposez maintenant des outils nécessaires pour travailler avec les packages npm qui nécessitent de compiler du code source.

      Une fois le runtime Node.js installé, passons à l’écriture d’une application Node.js.

      Étape 2 — Création d’une application Node.js

      Écrivons une application Hello World qui renvoie « Hello World » à toute demande HTTP. Cet exemple de demande vous aidera à mettre en place Node.js. Vous pouvez le remplacer par votre propre application : assurez-vous simplement de modifier votre application pour écouter sur les adresses IP et les ports appropriés.

      Tout d’abord, créons un exemple de demande appelée hello.js: 

      Ajoutez le code suivant dans le fichier :

      ~/hello.js

      const http = require('http');
      
      const hostname="localhost";
      const port = 3000;
      
      const server = http.createServer((req, res) => {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World!n');
      });
      
      server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
      });
      

      Enregistrez le fichier et quittez l’éditeur.

      Cette application Node.js écoute sur l’adresse (localhost) et le port (3000) spécifiés, et renvoie « Hello World ! » avec un code de réussite de 200 HTTP.  Comme nous sommes à l’écoute sur localhost, les clients distants ne pourront pas se connecter à notre application.

      Pour tester votre demande, tapez :

      Vous recevrez le résultat suivant :

      Output

      Server running at http://localhost:3000/

      Note : L’exécution d’une application Node.js de cette manière bloquera les commandes supplémentaires jusqu’à ce que l’application soit tuée en appuyant sur CTRL+C.

      Pour tester l’application, ouvrez une autre session de terminal sur votre serveur, et connectez-vous à localhost avec curl :

      • curl http://localhost:3000

      Si vous obtenez le résultat suivant, l’application fonctionne correctement et écoute à la bonne adresse et sur le bon port :

      Output

      Hello World!

      Si vous n’obtenez pas le résultat attendu, assurez-vous que votre application Node.js est en cours d’exécution et configurée pour écouter sur l’adresse et le port appropriés.

      Une fois que vous êtes sûr que cela fonctionne, arrêtez l’application (si ce n’est pas déjà fait) en appuyant sur CTRL+C.

      Étape 3 — Installer PM2

      Ensuite, nous allons installer PM2, un gestionnaire de processus pour les applications Node.js. PM2 permet de démoniser les applications afin qu’elles s’exécutent en arrière-plan comme un service.

      Utilisez npm pour installer la dernière version de PM2 sur votre serveur :

      • sudo npm install pm2@latest -g

      L’option -g indique à npm d’installer le module dans le monde entier, afin qu’il soit disponible dans tout le système.

      Commençons par utiliser la commande pm2 start​​​1​​​ pour exécuter votre application, hello.js, en arrière-plan :

      Cela ajoute également votre demande à la liste de processus de PM2, qui est produite chaque fois que vous lancez une demande :

      Output

      ... [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/hello.js in fork_mode (1 instance) [PM2] Done. ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ hello │ fork │ 0 │ online │ 0% │ 25.2mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

      Comme indiqué ci-dessus, PM2 attribue automatiquement un nom d'application (basé sur le nom de fichier, sans l’extension .js) et un identifiant PM2. PM2 conserve également d’autres informations, telles que le PID du processus, son état actuel et l’utilisation de la mémoire.

      Les applications qui tournent sous PM2 seront redémarrées automatiquement si l’application crashe ou est arrêtée, mais nous pouvons prendre une mesure supplémentaire pour que l’application soit lancée au démarrage du système en utilisant la sous-commande startup.  Cette sous-commande génère et configure un script de démarrage pour lancer PM2 et ses processus gérés aux démarrages du serveur :

      La dernière ligne de la sortie résultante comprendra une commande à exécuter avec les privilèges de superuser afin de configurer PM2 pour qu’il démarre au démarrage :

      Output

      [PM2] Init System found: systemd sammy [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Exécutez la commande à partir de la sortie, avec votre nom d’utilisateur à la place de sammy : 

      • sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Comme étape supplémentaire, nous pouvons sauvegarder la liste des processus PM2 et les environnements correspondants :

      Vous avez maintenant créé une unité systemd qui exécute pm2 pour votre utilisateur au démarrage. Cette instance pm2, à son tour, lance hello.js.

      Démarrer le service avec systemctl: 

      • sudo systemctl start pm2-sammy

      Si, à ce stade, un message d’erreur s’affiche, vous devrez peut-être redémarrer, ce que vous pouvez faire avec sudo reboot. 

      Vérifiez l’état de l’unité systemd :

      • systemctl status pm2-sammy

      Pour un aperçu détaillé de systemd, veuillez consulter Les Fondamentaux de Systemd : Travailler avec les services, les unités et le journal. 

      En plus de celles que nous avons couvertes, PM2 fournit de nombreuses sous-commandes qui vous permettent de gérer ou de rechercher des informations sur vos demandes.

      Arrêtez une application avec cette commande (spécifiez le nom ou l’identifiant de l’application PM2) :

      Redémarrer une application :

      • pm2 restart app_name_or_id

      Liste des applications actuellement gérées par PM2 :

      Obtenez des informations sur une application spécifique en utilisant son Nom d'application: 

      Le moniteur du processus PM2 peut être remonté avec la sous-commande monit.  Il affiche l’état de l’application, l’unité centrale et l’utilisation de la mémoire :

      Notez que l’exécution de pm2 sans aucun argument affichera également une page d’aide avec des exemples d’utilisation.

      Maintenant que votre application Node.js est exécutée et gérée par PM2, mettons en place le proxy inverse.

      Étape 4 — Configurer Nginx en tant que serveur proxy inverse

      Votre application fonctionne et écoute sur localhost, mais vous devez mettre en place un moyen pour que vos utilisateurs y accèdent. Pour cela, nous allons mettre en place le serveur web Nginx comme proxy inverse.

      Dans le tutoriel inclus dans les conditions préalables, vous configurez votre Nginx dans le fichier /etc/nginx/sites available/example.com. Ouvrez ce fichier pour le modifier :

      • sudo nano /etc/nginx/sites-available/example.com

      Dans le bloc de serveurs, vous devez avoir un location/bloc existant. Remplacez le contenu de ce bloc par la configuration suivante. Si votre application est configurée pour écouter sur un port différent, mettez à jour la partie en surbrillance avec le numéro de port correct :

      /etc/nginx/sites-available/example.com

      server {
      ...
          location / {
              proxy_pass http://localhost:3000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Cela permet de configurer le serveur pour qu’il réponde aux demandes à son root. En supposant que notre serveur soit disponible à l’adresse example.com, l’accès à https://example.com/ via un navigateur web enverrait la demande à hello.js, en écoute sur le port 3000 de localhost.

      Vous pouvez ajouter des blocs d’location supplémentaires au même bloc de serveur pour permettre l’accès à d’autres applications sur le même serveur. Par exemple, si vous exécutez également une autre application Node.js sur le port 3001, vous pourriez ajouter ce bloc de localisation pour y accéder via https://example.com/app2 :

      /etc/nginx/sites-available/example.com — Optional

      server {
      ...
          location /app2 {
              proxy_pass http://localhost:3001;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Une fois que vous avez fini d’ajouter les blocs de localisation pour vos applications, enregistrez le fichier et quittez votre éditeur.

      Assurez-vous que vous n’avez pas introduit d’erreurs de syntaxe en tapant :

      Redémarrez Nginx :

      • sudo systemctl restart nginx

      En supposant que votre application Node.js fonctionne, et que votre application et les configurations Nginx sont correctes, vous devriez maintenant pouvoir accéder à votre application via le proxy inverse Nginx. Essayez-le en accédant à l’URL de votre serveur (son adresse IP publique ou son nom de domaine).

      Conclusion

      Félicitations. Vous avez maintenant votre application Node.js fonctionnant derrière un proxy inverse Nginx sur un serveur Ubuntu 20.04. Cette configuration de proxy inverse est suffisamment souple pour permettre à vos utilisateurs d’accéder à d’autres applications ou à du contenu web statique que vous souhaitez partager.



      Source link