Autour du codeDevelopper toujours mieux
Posté le

Déployer une application WSGI en utilisant uWSGI et Nginx

Dans cet article, nous allons voir comment déployer une application python WSGI en utilisant le serveur uWSGI et le serveur Nginx.

Le but de Nginx et de servir de porte d'entrée. C'est lui qui recevra les requêtes en premier, il pourra alors servir directement les ressources statiques comme les fichiers CSS, les images ou les scripts JS, ou alors retransmettre la requête à uWSGI. uWSGI récupérera les requêtes venant de Nginx pour les passer aux applications après les avoir transformées en objets python. uWSGI utilisera le protocole uwsgi (en minuscule) pour communiquer avec Nginx.

Protocole HTTP ou uwsgi quelle est la différence ?

On va pouvoir choisir la façon de communiquer entre Nginx et uWSGI. Habituellement, Nginx envoie la requête directement en HTTP vers uWSGI, mais il peut également utiliser le protocole uwsgi (en minuscule). Cela ne change pas grand chose d'utiliser l'un ou l'autre niveau performance, que la requête soit transformée par Nginx ou pas uWSGI le travail devra être fait. Par contre le protocole uwsgi permet le passage de variables supplémentaires qui peut être utilisées si l'on souhaite faire des hôtes virtuels par exemple.

Installation de python3 et Nginx

On va partir du Debian 9 en commençant par installer python

apt-get update apt-get install build-essential python3 python3-dev

Puis l'on va installer Nginx

apt-get install nginx nginx-full

ainsi que l'utilitaire wget:

apt-get install wget

On va créer l'utilisateur app-manager qui sera le propriétaire de l'application.

useradd --shell /bin/bash -m --base-dir /var/www app-manager

Connectons-nous avec ce nouvel utilisateur, puis créons un environnement virtuel dans son répertoire home:

su - app-manager python3 -m venv wsgi-venv --without-pip source wsgi-venv/bin/activate wget -qO - https://bootstrap.pypa.io/get-pip.py | python -

On va installer uWSGI via pip et désactiver notre environnement virtuel. pip install uwsgi deactivate

Créer deux répertoires app qui contiendra l'application python et app-venv qui contiendra l'environnement virtuel de l'application.

Installation de l'application python

Pour l'exemple, j'ai créé une petite application nommée app_1 en utilisant le micro-framework Bottle l'application affiche une page web affichant avec la version de Bottle utiliser.

import bottle

@bottle.route('/')
def home():
    return '''<html>
                <head></head>
                <body>Hello Bottle {} !</body>
              </html>'''.format(bottle.__version__)
bottle==0.11.1

import bottle

import app

application = bottle.default_app()

bottle==0.11.1

On va copier app_1 dans le répertoire /var/www/app-manager/app/

Voici à quoi ressemble notre arborescence

|-- app
|   +-- app_1
|       |-- app.py
|       |-- requirements.txt
|       +-- wsgi.py
|-- app-venv
+-- wsgi-venv

On va créer un environnement virtuel et installer les dépendances de notre application.

python3 -m venv app-venv/app_1 --without-pip source app-venv/app_1/bin/activate wget -qO - https://bootstrap.pypa.io/get-pip.py | python - pip install -r app/app_1/requirements.txt deactivate

Configuration de uWSGI

[uwsgi]
chdir = /var/www/app-manager/app/app_1
home = /var/www/app-manager/app-venv/app_1
module = wsgi:application
uid = app-manager
gid = app-manager
socket = /var/www/app-manager/uwsgi.sock
chmod-socket=660
master = true
vacuum = true

chdir indique à uWSGI quel répertoire de travail utiliser. home indique quel environnement python utiliser uid et gid demandent à uWSGI d'utiliser l'utilisateur et le group app-manager pour exécuter les applications. socket et chmod-socket va créer une socket de type unix pour communiquer avec Nginx. Ce type de socket est dédié à la communication entre processus hébergé sur une machine. Elles sont plus rapide est plus sûr pour communiquer qu'une socket TCP/IP. vacuum demande à uWSGI de tenter de supprimer la socket au moment où il s'arrète.

Il nous reste plus qu'à lancer notre serveur uWSGI, on utilisera le paramètre -d pour indiquer le nom du fichier où seront écrit le logs et lancer uWSGI en mode daemon.

source wsgi-venv/bin/activate uwsgi -d log --ini uwsgi.ini

Configuration de Nginx

Repassons en root. Il va falloir permettre à Nginx de lire et écrire sur la socket créé par uWSGI. Pour cela, on va ajouter l'utilisateur www-data au group app-manager

usermod -aG app-manager www-data

Puis l'on va créer le fichier de configuration de notre site


server {
    listen 80;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/app-manager/uwsgi.sock;
    }
}

Maintenant que l'on a fini notre configuration de site, on va l'activer en créant un lien symbolique dans le répertoire sites-enabled

ln -s /etc/nginx/sites-available/app-manager /etc/nginx/sites-enabled/app-manager nginx -s reload

En cas de problèmes

Si jamais ça ne tourne pas comment vous le souhaitez, voici la liste des choses à faire pour trouver le problème.

Commençais par voir si votre application python fonctionne en lançant uWSGI avec l'option --http

uwsgi --http :9090 --wsgi wsgi:application --pyhome /var/www/app-manager/app-venv/app_1 -d log --chdir /var/www/app-manager/app/app_1/

Les options --wsgi, --pyhome et --chdir correspondent respectivement aux options module, home et chdir dans le fichier usgi.ini Jetez un coup d'œil dans les logs de uWSGI

cat log

Si uWSGI n'affiche aucun message d'erreur vérifier que la page de votre application s'affiche bien. $ wget -O- 127.0.0.1:9090

S'il n'y a rien à signaler, le problème se trouve peut-être au niveau de la configuration de Nginx. Consultez alors les logs de Nginx

cat /var/log/nginx/error.log