Comment servir les applications Flask avec uWSGI et Nginx sur Ubuntu 22.04

De Get Docs
Aller à :navigation, rechercher

Introduction

Dans ce guide, vous allez créer une application Python à l'aide du microframework Flask sur Ubuntu 22.04. La majeure partie de cet article portera sur la façon de configurer le serveur d'application uWSGI et comment lancer l'application et configurer Nginx pour qu'il agisse comme un proxy inverse frontal.

Conditions préalables

Avant de commencer ce guide, vous devez avoir :

  • Un serveur avec Ubuntu 22.04 installé et un utilisateur non root avec des privilèges sudo. Suivez notre guide de configuration initiale du serveur pour obtenir des conseils.
  • Nginx installé, en suivant Étapes 1 à 3 de Comment installer Nginx sur Ubuntu 22.04.
  • Un nom de domaine configuré pour pointer vers votre serveur. Vous pouvez en acheter un sur Namecheap ou en obtenir un gratuitement sur Freenom. Vous pouvez apprendre à faire pointer des domaines vers DigitalOcean en suivant la documentation pertinente sur les domaines et le DNS . Ce tutoriel part du principe que vous avez créé les enregistrements DNS suivants :
    • Un record A avec your_domain pointant vers l'adresse IP publique de votre serveur.
    • Un record A avec www.your_domain pointant vers l'adresse IP publique de votre serveur.

De plus, il peut être utile de se familiariser avec uWSGI, le serveur d'applications que vous allez configurer dans ce guide et la spécification WSGI. Cette discussion sur les définitions et les concepts passe en revue les deux en détail.

Étape 1 - Installation des composants à partir des référentiels Ubuntu

Votre première étape consistera à installer toutes les pièces dont vous avez besoin à partir des référentiels Ubuntu. Les packages que vous devez installer incluent pip, le gestionnaire de packages Python, pour gérer vos composants Python. Vous obtiendrez également les fichiers de développement Python nécessaires pour créer uWSGI.

Tout d'abord, mettez à jour l'index de package local :

sudo apt update

Installez ensuite les packages qui vous permettront de construire votre environnement Python. Ceux-ci comprendront python3-pip, ainsi que quelques packages et outils de développement supplémentaires nécessaires à un environnement de programmation robuste :

sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

Une fois ces packages en place, vous êtes prêt à passer à la création d'un environnement virtuel pour votre projet.

Étape 2 - Création d'un environnement virtuel Python

Un environnement virtuel Python est un répertoire de projet autonome qui contient des versions spécifiques de Python et les modules Python requis pour le projet donné. Ceci est utile pour isoler une application des autres sur le même système en gérant les dépendances de chacune séparément. Dans cette étape, vous allez configurer un environnement virtuel Python à partir duquel vous exécuterez votre application Flask.

Commencez par installer le python3-venv package, qui installera le venv module:

sudo apt install python3-venv

Créez ensuite un répertoire parent pour votre projet Flask :

mkdir ~/myproject

Déplacez-vous dans le répertoire après l'avoir créé :

cd ~/myproject

Créez un environnement virtuel pour stocker les exigences Python de votre projet Flask en saisissant :

python3.10 -m venv myprojectenv

Cela installera une copie locale de Python et pip dans un répertoire appelé myprojectenv dans votre répertoire de projet.

Avant d'installer des applications dans l'environnement virtuel, vous devez l'activer. Faites-le en tapant :

source myprojectenv/bin/activate

Votre invite changera pour indiquer que vous travaillez maintenant dans l'environnement virtuel. Cela ressemblera à ceci : (myprojectenv)[email protected]:~/myproject$.

Étape 3 - Configuration d'une application Flask

Maintenant que vous êtes dans votre environnement virtuel, vous pouvez installer Flask et uWSGI, puis commencer à concevoir votre application.

Tout d'abord, installez wheel avec l'instance locale de pip pour vous assurer que vos packages s'installeront même s'il leur manque des archives wheel :

pip install wheel

Remarque : Quelle que soit la version de Python que vous utilisez, lorsque l'environnement virtuel est activé, vous devez utiliser le pip commande (pas pip3).


Ensuite, installez Flask et uWSGI :

pip install uwsgi flask

Création d'un exemple d'application

Maintenant que vous disposez de Flask, vous pouvez créer un exemple d'application. Flask est un microframework. Il n'inclut pas de nombreux outils que des frameworks plus complets pourraient avoir et existe principalement sous la forme d'un module que vous pouvez importer dans vos projets pour vous aider à initialiser une application Web.

Bien que votre application puisse être plus complexe, dans cet exemple, vous allez créer votre application Flask dans un seul fichier, appelé myproject.py. Ouvert myproject.py utilisant nano ou votre éditeur de texte préféré :

nano ~/myproject/myproject.py

Le code de l'application vivra dans ce fichier. Il importera Flask et instanciera un objet Flask. Vous pouvez l'utiliser pour définir les fonctions que vous souhaitez exécuter lorsqu'une route spécifique est demandée :

~/monprojet/monprojet.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

Essentiellement, cela définit le contenu à présenter à quiconque accède au domaine racine. Enregistrez et fermez le fichier lorsque vous avez terminé. Si vous avez utilisé nano pour éditer le fichier, comme dans l'exemple précédent, faites-le en appuyant sur CTRL + X, Y, et alors ENTER.

Si vous avez suivi le guide de configuration initiale du serveur, vous devriez avoir un pare-feu UFW activé. Pour tester l'application, vous devez autoriser l'accès au port 5000:

sudo ufw allow 5000

Maintenant, vous pouvez tester votre application Flask en tapant :

python myproject.py

Vous verrez une sortie comme celle-ci, y compris un avertissement utile vous rappelant de ne pas utiliser cette configuration de serveur en production :

OutputWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Serving Flask app 'myproject'
 * Debug mode: off
 * Running on all addresses (0.0.0.0)
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://127.0.0.1:5000
 * Running on http://your_server:5000 (Press CTRL+C to quit)

Visitez l'adresse IP de votre serveur suivie de :5000 dans votre navigateur Web :

http://your_server_ip:5000

Vous verrez quelque chose comme ceci :

Lorsque vous avez terminé, appuyez sur CTRL + C dans la fenêtre de votre terminal pour arrêter le serveur de développement Flask.

Création du point d'entrée WSGI

Ensuite, créez un fichier qui servira de point d'entrée pour votre application. Cela indiquera à votre serveur uWSGI comment interagir avec lui.

Appelez le dossier wsgi.py:

nano ~/myproject/wsgi.py

Dans ce fichier, importez l'instance Flask depuis votre application puis exécutez-la :

~/monprojet/wsgi.py

from myproject import app

if __name__ == "__main__":
    app.run()

Enregistrez et fermez le fichier lorsque vous avez terminé.

Étape 4 - Configuration de uWSGI

Votre application est maintenant rédigée avec un point d'entrée établi. Vous pouvez passer à la configuration de uWSGI.

Tester si uWSGI peut servir l'application

Dans un premier temps, testez pour vous assurer que uWSGI peut servir correctement votre application en lui passant le nom de votre point d'entrée. Ceci est construit par le nom du module (moins le .py extension) plus le nom de l'appelable dans l'application. Dans le cadre de ce tutoriel, le nom du point d'entrée est wsgi:app.

Spécifiez également le socket afin qu'il soit démarré sur une interface accessible au public, ainsi que le protocole, afin qu'il utilise HTTP au lieu du uwsgi protocole binaire. Utilisez le même numéro de port, 5000, que vous avez ouvert précédemment :

uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

Visitez l'adresse IP de votre serveur avec :5000 à nouveau ajouté à la fin dans votre navigateur Web :

http://your_server_ip:5000

Vous verrez à nouveau la sortie de votre application :

Lorsque vous avez confirmé qu'il fonctionne correctement, appuyez sur CTRL + C dans la fenêtre de votre terminal.

Vous en avez maintenant terminé avec votre environnement virtuel, vous pouvez donc le désactiver :

deactivate

Toutes les commandes Python utiliseront à nouveau l'environnement Python du système.

Création d'un fichier de configuration uWSGI

Vous avez testé que uWSGI est capable de servir votre application, mais vous voudrez quelque chose de plus robuste pour une utilisation à long terme. Vous pouvez créer un fichier de configuration uWSGI avec les options appropriées pour cela.

Placez ce fichier dans votre répertoire de projet et appelez-le myproject.ini:

nano ~/myproject/myproject.ini

À l'intérieur, démarrez le fichier avec le [uwsgi] header afin que uWSGI sache appliquer les paramètres. En dessous, spécifiez le module lui-même - en vous référant au wsgi.py fichier moins l'extension - et l'appelable dans le fichier, app:

~/monprojet/monprojet.ini

[uwsgi]
module = wsgi:app

Ensuite, dites à uWSGI de démarrer en mode maître et de générer cinq processus de travail pour répondre aux demandes réelles :

~/monprojet/monprojet.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

Lors des tests, vous avez exposé uWSGI sur un port réseau. Cependant, vous allez utiliser Nginx pour gérer les connexions client réelles, qui transmettront ensuite les demandes à uWSGI. Étant donné que ces composants fonctionnent sur le même ordinateur, un socket Unix est préférable car il est plus rapide et plus sécurisé. Appelez la prise myproject.sock et placez-le dans ce répertoire.

Ensuite, modifiez les autorisations sur le socket. Vous donnerez au groupe Nginx la propriété du processus uWSGI plus tard, vous devez donc vous assurer que le propriétaire du groupe du socket peut lire les informations à partir de celui-ci et y écrire. Aussi, ajoutez le vacuum option et définissez-la sur true ; cela nettoiera le socket lorsque le processus s'arrêtera :

~/monprojet/monprojet.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

La dernière chose à faire est de régler le die-on-term option. Cela peut aider à garantir que le système init et uWSGI ont les mêmes hypothèses sur la signification de chaque signal de processus. Cette configuration aligne les deux composants du système, implémentant le comportement attendu :

~/monprojet/monprojet.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

Vous avez peut-être remarqué que ces lignes ne spécifient pas de protocole comme vous l'avez fait à partir de la ligne de commande. En effet, par défaut, uWSGI parle en utilisant le uwsgi protocole, un protocole binaire rapide conçu pour communiquer avec d'autres serveurs. Nginx peut parler ce protocole de manière native, il est donc préférable de l'utiliser plutôt que de forcer la communication par HTTP.

Lorsque vous avez terminé, enregistrez et fermez le fichier.

Avec cela, uWSGI est configuré sur votre système. Afin de vous offrir plus de flexibilité dans la gestion de votre application Flask, vous pouvez désormais la configurer pour qu'elle s'exécute en tant que service systemd.

Étape 5 - Création d'un fichier d'unité systemd

Systemd est une suite d'outils qui fournit un modèle d'initialisation rapide et flexible pour la gestion des services système. La création d'un fichier d'unité systemd permettra au système d'initialisation d'Ubuntu de démarrer automatiquement uWSGI et de servir l'application Flask à chaque démarrage du serveur.

Créer un fichier unité se terminant par .service au sein de la /etc/systemd/system répertoire pour commencer :

sudo nano /etc/systemd/system/myproject.service

A l'intérieur, commencez par le [Unit] section, qui est utilisée pour spécifier les métadonnées et les dépendances. Ensuite, mettez une description du service ici et dites au système d'initialisation de ne le démarrer qu'une fois que la cible de mise en réseau a été atteinte :

/etc/systemd/system/monprojet.service

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

Ensuite, créez le [Service] section. Cela spécifiera l'utilisateur et le groupe sous lesquels vous souhaitez que le processus s'exécute. Donnez à votre compte d'utilisateur habituel la propriété du processus puisqu'il possède tous les fichiers pertinents. Donnez ensuite la propriété du groupe au groupe www-data afin que Nginx puisse communiquer avec les processus uWSGI (il s'agit du groupe avec lequel Nginx s'exécute par défaut sur Ubuntu). N'oubliez pas de remplacer ici le nom d'utilisateur par votre nom d'utilisateur :

/etc/systemd/system/monprojet.service

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data

Ensuite, tracez le répertoire de travail et définissez le PATH variable d'environnement afin que le système init sache que les exécutables du processus se trouvent dans votre environnement virtuel. Spécifiez également la commande pour démarrer le service. Systemd nécessite que vous donniez le chemin d'accès complet à l'exécutable uWSGI, qui est installé dans votre environnement virtuel. Ici, on passe le nom du .ini fichier de configuration que vous avez créé dans votre répertoire de projet.

N'oubliez pas de remplacer le nom d'utilisateur et les chemins du projet par vos propres informations :

/etc/systemd/system/monprojet.service

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

Enfin, ajoutez un [Install] section. Cela indiquera à systemd à quoi lier ce service si vous lui permettez de démarrer au démarrage. Dans ce cas, configurez le service pour qu'il démarre lorsque le système multi-utilisateurs standard est opérationnel :

/etc/systemd/system/monprojet.service

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

[Install]
WantedBy=multi-user.target

Avec cela, votre fichier de service systemd est terminé. Enregistrez et fermez-le maintenant.

Avant de démarrer le service uWSGI, vous devrez modifier l'autorisation, car le Nginx www-data l'utilisateur ne pourra pas lire les fichiers de votre répertoire personnel par défaut dans Ubuntu 22.04 et versions ultérieures. Cela peut vous empêcher de servir des applications Web à partir de votre répertoire personnel. Une solution rapide consiste à modifier le groupe associé à votre répertoire personnel à l'aide de chgrp:

sudo chgrp www-data /home/sammy

Cela permettra à Nginx de voir le contenu de votre répertoire personnel, dont il a besoin pour accéder au fichier socket. Il n'exposera aucun des fichiers de votre répertoire personnel au Web.

Vous pouvez maintenant démarrer le service uWSGI que vous avez créé :

sudo systemctl start myproject

Activez-le ensuite pour qu'il démarre au démarrage :

sudo systemctl enable myproject

Vérifiez l'état :

sudo systemctl status myproject

Vous verrez une sortie comme celle-ci :

Output● myproject.service - uWSGI instance to serve myproject
     Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: ena>
     Active: active (running) since Fri 2022-08-05 17:22:05 UTC; 6s ago
   Main PID: 4953 (uwsgi)
      Tasks: 6 (limit: 2327)
     Memory: 20.9M
        CPU: 241ms
     CGroup: /system.slice/myproject.service
             ├─4953 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4954 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4955 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4956 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             ├─4957 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
             └─4958 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

Si vous voyez des erreurs, assurez-vous de les résoudre avant de poursuivre le didacticiel. Sinon, vous pouvez passer à la configuration de votre installation Nginx pour transmettre les requêtes au myproject.sock prise.

Étape 6 - Configuration de Nginx pour les demandes de proxy

Votre serveur d'application uWSGI est maintenant opérationnel et attend les requêtes sur le fichier socket dans le répertoire du projet. Dans cette étape, vous allez configurer Nginx pour transmettre les requêtes Web à ce socket en utilisant le uwsgi protocole.

Commencez par créer un nouveau fichier de configuration de bloc de serveur dans Nginx sites-available annuaire. Pour rester en ligne avec le rest du guide, l'exemple suivant s'y réfère comme myproject:

sudo nano /etc/nginx/sites-available/myproject

Ouvrez un bloc de serveur et dites à Nginx d'écouter sur le port par défaut 80. De plus, dites-lui d'utiliser ce bloc pour les demandes de nom de domaine de votre serveur :

/etc/nginx/sites-available/monprojet

server {
    listen 80;
    server_name your_domain www.your_domain;
}

Ensuite, ajoutez un bloc d'emplacement qui correspond à chaque demande. Dans ce bloc, incluez le uwsgi_params fichier qui spécifie certains paramètres généraux uWSGI qui doivent être définis. Transmettez ensuite les requêtes au socket que vous avez défini à l'aide de la commande uwsgi_pass directif:

/etc/nginx/sites-available/monprojet

server {
    listen 80;
    server_name your_domain www.your_domain;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/sammy/myproject/myproject.sock;
    }
}

Enregistrez et fermez le fichier lorsque vous avez terminé.

Pour activer la configuration du bloc de serveur Nginx que vous venez de créer, liez le fichier au sites-enabled annuaire:

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Lorsque vous avez installé Nginx, le processus configure automatiquement un fichier de configuration de bloc de serveur nommé default dans le sites-available répertoire, puis créé un lien symbolique entre ce fichier et le sites-enabled annuaire. Si vous laissez ce lien symbolique en place, le default la configuration bloquera le chargement de votre site. Vous pouvez supprimer le lien avec la commande suivante :

sudo unlink /etc/nginx/sites-enabled/default

Ensuite, vous pouvez tester les erreurs de syntaxe en tapant :

sudo nginx -t

Si cela revient sans indiquer de problème, redémarrez le processus Nginx pour lire la nouvelle configuration :

sudo systemctl restart nginx

Enfin, ajustez à nouveau le pare-feu. Vous n'avez plus besoin d'accéder via le port 5000, vous pouvez donc supprimer cette règle. Ensuite, vous pouvez autoriser l'accès au serveur Nginx :

sudo ufw delete allow 5000
sudo ufw allow 'Nginx Full'

Vous pourrez désormais accéder au nom de domaine de votre serveur dans votre navigateur Web :

http://your_domain

Vous verrez la sortie de votre application :

Si vous rencontrez des erreurs, essayez de vérifier les points suivants :

  • sudo less /var/log/nginx/error.log: vérifie les journaux d'erreurs Nginx.
  • sudo less /var/log/nginx/access.log: vérifie les journaux d'accès Nginx.
  • sudo journalctl -u nginx: vérifie les journaux de processus Nginx.
  • sudo journalctl -u myproject: vérifie les journaux uWSGI de votre application Flask.

Étape 7 - Sécurisation de l'application

Pour vous assurer que le trafic vers votre serveur reste sécurisé, obtenez un certificat SSL pour votre domaine. Il existe plusieurs façons de procéder, notamment en obtenant un certificat gratuit de Let's Encrypt, en générant un certificat auto-signé ou en en achetant un auprès d'un fournisseur commercial. Par souci de rapidité, ce tutoriel explique comment obtenir un certificat gratuit de Let's Encrypt.

Tout d'abord, installez Certbot et son plugin Nginx avec apt:

sudo apt install certbot python3-certbot-nginx

Certbot propose différentes manières d'obtenir des certificats SSL via des plugins. Le plugin Nginx se chargera de reconfigurer Nginx et de recharger la configuration chaque fois que nécessaire. Pour utiliser ce plugin, tapez ce qui suit :

sudo certbot --nginx -d your_domain -d www.your_domain

Cela fonctionne certbot avec le --nginx plug-in, utilisation -d pour spécifier les noms pour lesquels vous souhaitez que le certificat soit valide.

Si c'est la première fois que vous courez certbot sur ce serveur, vous serez invité à saisir une adresse e-mail et à accepter les conditions d'utilisation. Après avoir fait cela, certbot communiquera avec le serveur Let's Encrypt, puis lancera un défi pour vérifier que vous contrôlez le domaine pour lequel vous demandez un certificat.

La configuration sera mise à jour et Nginx se rechargera pour récupérer les nouveaux paramètres. certbot se terminera par un message vous indiquant que le processus a réussi et où vos certificats sont stockés :

OutputSuccessfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your_domain/privkey.pem
This certificate expires on 2022-11-03.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject
Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject
Congratulations! You have successfully enabled HTTPS on https://your_domain and https://www.your_domain

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Si vous avez suivi les instructions d'installation de Nginx dans les prérequis, vous n'aurez plus besoin de l'allocation de profil HTTP redondant :

sudo ufw delete allow 'Nginx HTTP'

Pour vérifier la configuration, accédez à nouveau à votre domaine en utilisant https://:

https://your_domain

Vous verrez à nouveau la sortie de votre application, ainsi que l'indicateur de sécurité de votre navigateur, qui devrait indiquer que le site est sécurisé.

Conclusion

Dans ce guide, vous avez créé et sécurisé une application Flask dans un environnement virtuel Python. Ensuite, vous avez créé un point d'entrée WSGI afin que tout serveur d'applications compatible WSGI puisse s'interfacer avec lui, puis configuré le serveur d'applications uWSGI pour fournir cette fonction. Ensuite, vous avez créé un fichier de service systemd pour lancer automatiquement le serveur d'applications au démarrage. Vous avez également créé un bloc de serveur Nginx qui transmet le trafic du client Web au serveur d'application, relayant ainsi les demandes externes et sécurisé le trafic vers votre serveur avec Let's Encrypt.

Flask est un cadre flexible destiné à fournir à vos applications des fonctionnalités sans être trop restrictif sur la structure ou la conception. Vous pouvez utiliser la pile générale décrite dans ce guide pour servir les applications flask que vous concevez.