CentOS7, Django, virtualenv, uwsgi et nginx. On déploie !

Cela peut paraître un peu complexe, mais en faite pas du tout ! Utiliser nginx avec une application Django c’est assez simple. Je vais vous le prouver !

Pré-requis

Nous allons faire pointer le domaine my_site.local vers notre app Django.
On part du CentOS7 fraîchement installée pour l’exemple.

Installation de base

Tout d’abord on installe l’ensemble des paquet nécessaire pour tout faire fonctionner.

# yum install epel-release
# yum install nginx python-pip python-devel
# yum group install "Development Tools"

Ensuite on install virtualenv et uwsgi via pip directement sur le système

# pip install uwsgi virtualenv

Configuration de votre app Django

On va créer un utilisateur my_site. C’est dans son $HOME que nous mettrons l’application Django.

# useradd mon_site
# su mon_site

Maintenant que nous sommes connecté avec l’utilisateur mon_site, nous allons récupérer le projet.
Dans notre exemple, le projet django sera dans un dossier nommé mon_site.

Pour faire simple, le chemin du fichier manage.py sera /home/mon_site/mon_site/manage.py

La première chose est de configurer les dossiers media et static dans le fichier settings.py

MEDIA_ROOT = BASE_DIR + '/media/'
STATIC_ROOT = BASE_DIR + '/static/'

Il faut créer le virtualenv. Il sera dans le dossier /home/mon_site/mon_site/

$ cd /home/mon_site/mon_site/
$ virtualenv env
$ source env/bin/activate
$ pip install -r requirements.txt
$ python manage.py collectstatic
$ deactivate

Votre projet Django est prêt (je vous laisse vous débrouiller pour la base de données, toussa).

Configuration uWSGI

Petite explication avant de commencer. Le fonctionnement est assez simple, lorsque vous allez essayer de vous connecter à votre site avec votre navigateur, celui-ci va se connecter à Nginx.
nginx ne sais pas directement communiquer avec Django pour récupérer la page à renvoyer. Il faut une interface entre Nginx et Django, ça sera uWSGI.

web browser -> Nginx -> uWSGI -> Django app

web browser <- Nginx <- uWSGI <- Django app

Vous pouvez lancer uWSGI en ligne de commande. Cela donnerais ceci :

$ uwsgi --chdir=/home/mon_site/mon_site/ \
    --module=my_site.wsgi \
    --env DJANGO_SETTINGS_MODULE=my_site.settings \
    --master --pidfile=/tmp/my_site-master.pid \
    --http=:8001 \ # peut aussi être un fichier socket avec --socket=/tmp/my_site.sock, dans le cas ou le serveur nginx et uwsgi sont sur le même serveur.
    --processes=5 \ # nombre de processus
    --vacuum \ # clear l'environment à l'exit
    --home=/home/mon_site/mon_site/env # chemain vers le virtualenv
# Vous pouvez aussi ajouter le paramètre --daemonize=/home/mon_site/mon_site/wsgi.log pour faire tourner directement en background

En lançant cette commande, vous pourrez accéder à votre site via mon_site.local:8001

Note: On peut se demander pourquoi utiliser Nginx, alors que uWSGi fait déjà le job. En faite simplement parce que Nginx va aussi nous servir à servir les fichiers css, js, img..., qu'il va pouvoir compresser les pages renvoyées, etc...

Pour simplifier le déploiement, nous allons mettre ces informations dans un fichier .ini

# mkdir -p /etc/uwsgi/sites

et on va créer le fichier /etc/uwsgi/sites/my_site.local.ini avec le contenu suivant

[uwsgi]
 
chdir           = /home/mon_site/mon_site/
module          = my_site.wsgi
home            = /home/mon_site/mon_site/env
master          = true
pidfile         = /tmp/my_site-master.pid
processes       = 5
socket          = :8001
vacuum           = true
daemonize        = /home/mon_site/mon_site/wsgi.log

Vous constaterez que l'on deamonize uwsgi dans cette configuration. On a aussi changer http par socket, pour éviter que l'on se connecte à uwsgi directement depuis un navigateur web.

À partir de là nous pouvons lancer uwsgi en ligne de commande uwsgi --ini /etc/uwsgi/sites/my_site.local.ini, mais nous allons plutot utiliser systemd pour lancer uwsgi.
On va créer le fichier : /etc/systemd/system/uwsgi.service contenant :

[Unit]
Description=uWSGI Emperor service
 
[Service]
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
 
[Install]
WantedBy=multi-user.target

Nous utilisons le mode emperor de uWSGI qui permet de lancer une instance de uWSGI pour chaque fichier configuration présent dans /etc/uwsgi/sites/ (pratique si vous hébergez plusieurs sites !)

Pour lancer uWSGI :

systemctl start uwsgi

Configuration nginx

Maintenant que uWSGI est en place, il nous reste Nginx à configurer.
Il faut créer le ficher /etc/nginx/conf.d/mon_site.local

# configuration pour la connexion à uwsgi
upstream django {
    server 127.0.0.1:8001; # en passant par un port web
    # server unix:///tmp/mon_site.local.sock; # en passant par le socket.
}
 
# configuration du serveur
server {
    listen      80;for
    server_name mon_site.local;
    charset     utf-8;
 
    # Les médias (fichiers envoyés par les utilisateurs en général)
    location /media  {
        alias /home/mon_site/mon_site/media;
    }
 
    location /static {
        alias /home/mon_site/mon_site/static;
    }
 
    # Tout ce qui n'est pas static ou media est envoyé à Django
    location / {
        uwsgi_pass  django;
        uwsgi_param QUERY_STRING $query_string;
        uwsgi_param REQUEST_METHOD $request_method;
        uwsgi_param CONTENT_TYPE $content_type;
        uwsgi_param CONTENT_LENGTH $content_length;
        uwsgi_param REQUEST_URI $request_uri;
        uwsgi_param PATH_INFO $document_uri;
        uwsgi_param DOCUMENT_ROOT $document_root;
        uwsgi_param SERVER_PROTOCOL $server_protocol;
        uwsgi_param REMOTE_ADDR $remote_addr;
        uwsgi_param REMOTE_PORT $remote_port;
        uwsgi_param SERVER_ADDR $server_addr;
        uwsgi_param SERVER_PORT $server_port;
        uwsgi_param SERVER_NAME $server_name;    
    }
}

On lance Nginx:

systemctl start nginx

SELinux

Il se peut que SELinux bloque la connexion entre Nginx et uWSGI, et qu'il empêche Nginx de fournir correctement les fichiers statics... Dans ce cas la :

setsebool httpd_can_network_connect on -P
chcon -Rt httpd_sys_content_t /home/my_site/my_site/

Et voilà

Si vous vous rendez sur my_site.local, ça devrait fonctionner.

Aymeric DERBOIS

J'ai 27 ans et je suis développeur. Je travail la plupart du temps sur des techno web, mais pas que. Étant à l'affût des nouveautés, j'adore découvrir tout et n'importe quoi dans l'informatique. Je suis amoureux de CakePHP et j'utilise au quotidien Django. Je suis très ouvert d'esprit :). J'aime bien utiliser AngularJS aussi de temps à autre pour faire du front. Au quotidien j'utilise Fedora/Ubuntu pour le desktop et CentOS pour mes serveurs. Par ailleurs je maîtrise le C/C++/Python/PHP/...

More Posts - Website

Follow Me:
Twitter

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.