CentOS7, Django, virtualenv, uwsgi et nginx. On déploie !
Cet article est ancien
Cet article date de 2015, il est possible que certaines informations ne soient plus à jour. Par ailleurs un certain nombre de bonnes pratiques ne sont pas correctement appliquées. Merci de prendre celui-ci avec des pincettes.
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 d'une 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 installe 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 \
--processes=5 \
--vacuum \ # clear l'environment à l'exit
--home=/home/mon_site/mon_site/env
# 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 plutôt 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.