• 4 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 2/19/20

Utilisez le serveur HTTP Nginx

Dans les chapitres précédents vous avez réservé un espace sur un serveur, téléchargé les différents logiciels et créé la base de données. Votre projet Django est prêt à être montré !

Vous avez lancé le serveur avec brio en tapant la commande python disquaire/manage.py runserver. Malheureusement, l'adresse http://127.0.0.1:8000/ n'affiche rien ! Vous devez utiliser l'adresse IP publique pour y accéder !

L'adresse publique ? Il existe différentes adresses ?

Tout à fait ! Chaque ordinateur possède notamment une adresse privée et une publique.

La première lui est propre et sert à représenter un ordinateur sur un réseau local. Elle n'est pas accessible par Internet.

L'adresse publique, elle, est un identifiant unique qui est bien accessible par Internet. Ainsi, vous pouvez accéder à votre serveur en tapant l'adresse IP publique, donnée par Digital Ocean, mais non l'adresse privée !

Pour en savoir plus, je vous conseille de lire le début du chapitre Analyser le réseau et filtrer le trafic avec un pare-feu.

Alors, comment faire ? Bien entendu, vous n'allez pas changer la configuration de Django. Vous allez configurer un logiciel pour transférer les requêtes effectuées sur l'IP publique à l'IP privée. Il s'agit d'un serveur web ou serveur HTTP.

Il en existe plusieurs et vous avez peut-être déjà entendu parler d'Apache ou de Nginx. Dans ce chapitre, vous découvrirez ce serveur HTTP ! Dans une seconde partie, vous découvrirez comment ajouter un fichier de configuration pour afficher l'application Django.

Engine-X, Nginx pour les intimes

Nginx (que l'on prononce ènjyne-x) est un logiciel libre de serveur web, écrit par Igor Sysoev, dont le développement a débuté en 2002 pour les besoins d'un site russe à très fort trafic (Rambler). Il est rapidement devenu très populaire grâce à sa syntaxe facile à prendre en mains. En septembre 2017, Nginx est utilisé par 20,75% des sites actifs dans le monde selon Netcraft.

Téléchargez-le sur le serveur en tapant la commande suivante :

sudo apt-get install nginx

Nginx étant installé, tout trafic arrivant à votre serveur sera géré par le serveur web. Faites l'essai : tapez l'adresse IP dans votre navigateur !

Vous voyez à présent un message de la part d'Nginx qui indique que tout fonctionne correctement. Afin de comprendre comment ce message a été généré, regardez la configuration par défaut.

Configuration par défaut

La configuration par défaut de Nginx est située dans etc/nginx/sites-enabled/. La voici :

default

##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #       include snippets/fastcgi-php.conf;
        #
        #       # With php7.0-cgi alone:
        #       fastcgi_pass 127.0.0.1:9000;
        #       # With php7.0-fpm:
        #       fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #       deny all;
        #}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#       listen 80;
#       listen [::]:80;
#
#       server_name example.com;
#
#       root /var/www/example.com;
#       index index.html;
#
#       location / {
#               try_files $uri $uri/ =404;
#       }
#}

Je ne comprends pas bien la syntaxe. Cela ressemble vaguement à du CSS...

Exact ! C'est assez similaire mais la ressemblance est trompeuse. Voyons tout de suite la syntaxe !

Le fichier de configuration contient plusieurs éléments :

  • # : commentaire. Chaque ligne commençant par un croisillon (souvent appelé dièse) ne sera pas évaluée par Nginx. Vous pouvez ainsi donner plus de détails si vous le souhaitez. Les développeurs les utilisent également pour activer ou désactiver facilement certains paramètres.

  • listen 80; : directive. Une ligne commence par un mot-clé. Il prend au moins un argument et se finit par un point-virgule. Contrairement à CSS, chaque mot-clé est séparé de l'argument par un espace et non pas par deux-points. Pensez-y ! ;) On appelle chaque mot-clé une directive.

  • location / {try_files $uri $uri/ =404;} : bloc. Certains arguments de mots-clés contiennent des accolades regroupant d'autres lignes de configuration. Exactement comme en CSS, chaque directive contenue dans l'accolade a une répercussion sur l'argument. Nous appelons cela un bloc.

  • L'indentation n'est pas une obligation mais je vous conseille de garder votre code lisible en ajoutant 4 espaces à gauche pour chaque niveau.

Vous remarquerez également que certaines accolades contiennent elles-mêmes d'autres accolades. Exactement comme en HTML, une balise peut en contenir une autre ! Dans ce cas, les sous-directives auront une répercussion à la fois sur la directive mère et sur la grand-mère.

Maintenant que vous connaissez la syntaxe, regardons de plus près le fichier. Il est organisé en deux parties. La majeure partie contient des directives réellement appliquées. Quant à la fin du fichier, il donne un exemple facile à reprendre. Commençons par expliciter certaines directives avant de détailler l'exemple.

La directive server permet de regrouper les différentes actions à réaliser pour un groupe. Dans le jargon, un groupe est un "serveur virtuel". En savoir plus

La ligne listen 80 default_server; indique que le port 80 est utilisé. Ainsi, tout trafic à l'URL "adresseip:80" sera traité par cet ensemble (mais, par exemple, pas celui utilisant le port :3000 !). En savoir plus

Vous avez remarqué que notre serveur web a affiché une page d'information en HTML. Où se trouve-t-elle ? Si vous cherchez dans le dossier etc/nginx, vous ne la verrez pas. Et pour cause, elle se trouve bien ailleurs ! Nginx sait comment la trouver grâce à root qui indique le dossier de base des fichiers à renvoyer. Ainsi, la directive root /var/www/html; dit : "Tous les documents qui sont concernés par ce groupe sont dans le dossier var/www/html".

Quant à la page d'accueil, elle est désignée par index : index index.html index.htm index.nginx-debian.html;. Regardez dans le dossier /var/www/html : vous y découvrirez effectivement le fichier index.nginx-debian.html.

Pourquoi plusieurs noms de fichiers sont passés en argument ?

Les arguments sont indiqués par ordre de priorité : plus ils sont proches de la directive, plus ils sont prioritaires. Exactement comme en CSS ! Ainsi, la configuration par défaut permet plusieurs noms de fichier.

La directive server_name permet d'indiquer quelle est le nom de domaine, ou l'adresse IP, ciblée par le groupe. Elle prend en paramètre une expression régulière. Vous n'en utiliserez pas dans ce cours, rassurez-vous ! Mais sachez que le symbole _ représente, pour Nginx, tous les noms de domaines. En savoir plus dans la documentation.

La directive suivante est location. Elle fait référence au chemin relatif qui est dans l'URL (l'URI) et prend en argument une expression régulière ou une chaine de caractères. Petite subtilité : si l'argument est une chaîne, l'URI doit commencer par elle. ! Dans cet exemple, seule une barre oblique est indiquée : /. Cela signifie que toutes les requêtes dont l'URI commence par / devront appliquer les directives du bloc. En savoir plus

Enfin, la dernière est try_files. Elle vérifie l'existence des fichiers passés en argument par ordre de priorité. L'exemple indique d'ailleurs : try_files $uri $uri/ =404;. Que va-t-il se passer ? Nginx va chercher le fichier sur le serveur en suivant le chemin passé dans l'URL. Par exemple, il naviguera dans root_file/static/metallica.png si l'URI est /static/metallica.png. S'il est introuvable, il essaiera de trouver le dossier. Par exemple : /static/metallica.png/. Si le fichier est toujours aux abonnés absents, il renverra une erreur 404.

Bravo ! 👏 Vous avez désormais une bien meilleure compréhension de Nginx ! Il est temps de pratiquer !

Mise en application

La fin du fichier de configuration par défaut donne quelques clés pour ajouter un nouveau serveur virtuel mais vous pouvez aller plus loin !

Vous pourriez tout à fait décommenter les directives données en exemple à la fin du fichier de configuration par défaut mais cela deviendrait vite le bazar. Il est d'usage de créer un fichier par site !

Je peux héberger plusieurs sites sur le même serveur ?

Hé oui ! Nginx est très puissant ! Vous pouvez créer autant de serveurs virtuels que vous le désirez. Ainsi, il est tout à fait possible d'utiliser Nginx sur un même serveur pour des sites différents !

Création d'un fichier de configuration

Par convention, les fichiers de configuration sont regroupés dans le dossier sites-enabled. Ils sont tous pris en compte de la même manière. Ouvrez-le : vous y découvrirez un fichier default.

$ vi /etc/nginx/sites-enabled

" ============================================================================
" Netrw Directory Listing                                        (netrw v155)
"   /etc/nginx/sites-enabled
"   Sorted by      name
"   Sort sequence: [\/]$,\<core\%(\.\d\+\)\=\>,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\.obj$,\.info$,\.swp$,\.bak$,\~$
"   Quick Help: <F1>:help  -:go up dir  D:delete  R:rename  s:sort-by  x:special
" ==============================================================================
../
./
default@                          --> /etc/nginx/sites-available/default

Vous remarquerez qu'il est un peu spécial : il contient un @... Je vous ai menti, il ne s'agit pas d'un fichier mais d'un lien symbolique ! Le vrai fichier se trouve à l'adresse indiquée par la flèche.

Vous devez donc :

  • créer un nouveau fichier dans sites-available ;

  • ajouter un lien symbolique dans sites-enabled grâce à la commande ln.

C'est parti !

celinems@disquaire:/etc/nginx/$ sudo touch sites-available/disquaire
[sudo] password for celinems:
celinems@disquaire:/etc/nginx/$ sudo ln -s /etc/nginx/sites-available/disquaire /etc/nginx/sites-enabled

Voyons désormais comment lier le trafic entrant à l'application Django. Celle-ci contient d'ailleurs deux formats de fichiers très différents :

  • les fichiers statiques (CSS, JavaScript, images...) ;

  • les fichiers dynamiques qui ont besoin de l'application Django.

Vous allez utiliser Nginx pour les actions suivantes :

  • si un fichier statique est demandé, affiche-le sans passer par l'application ;

  • sinon, redirige le trafic vers l'application Django.

Commencez par rediriger le trafic vers l'application !

Servir l'application Django

Ouvrez le document etc/nginx/sites-available/disquaire que vous venez de créer. Allez, vous avez toutes les clés en main pour le remplir par vous-même ! Faites l'exercice puis regardez ma solution.

nginx/sites-available/disquaire

server { 
        
    listen 80; server_name 178.62.117.192; 
    root /home/celinems/disquaire/;
        
    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
        proxy_pass http://127.0.0.1:8000;
    }
        
}

Détaillons les directives :

  • listen 80 : le port par défaut de toute requête HTTP est 80.

  • server_name 178.62.117.192; : l'adresse IP de mon serveur. Ainsi, je cible toute requête HTTP dont le nom d'hôte est 178.62.117.192. Vous pouvez également passer un nom de domaine !

  • root home/celinems/disquaire/; : tout fichier demandé devra être trouvé dans ce dossier de base. Ainsi, tous les chemins indiqués par la suite seront relatifs à cette racine.

  • la directive location prend deux paramètres : l'URI et les directives à appliquer. Ici, j'indique que toute URI commençant par / doit être redirigée vers l'URL http://127.0.0.1:8000. De fait, toutes les URL seront donc traitées par l'application Django.

Nginx ne recharge pas automatiquement les configurations. Vous devez lui indiquer manuellement en exécutant la commande reload :

celinems@disquaire:/etc/nginx$ sudo service nginx reload

Allez, lancez un serveur en tapant la commande ./manage.py runserver. Puis ouvrez un nouveau terminal et connectez-vous de nouveau en SSH. Ainsi, le serveur Django tournera pendant que vous configurerez Nginx !

Naviguez sur l'URL de votre site : une erreur 400 apparait !

Pas de panique, Django vous avertit simplement que le nom de domaine n'est pas autorisé ! Vous devez modifier le fichier settings.py en conséquence.

settings.py

# ...
ALLOWED_HOSTS = ['178.62.117.192']
# ...

Relancez le serveur : ça fonctionne !

Servir les fichiers statiques

L'application actuelle utilise la librairie WhiteNoise pour servir les fichiers statiques. Étant donné qu'il s'agit d'une tâche dans laquelle Nginx excelle, je vous invite à désactiver la librairie et à utiliser le serveur web.

Supprimez les lignes suivantes du fichier de configuration de l'application Django :

settings.py

MIDDLEWARE = [
    # ...
    # 'whitenoise.middleware.WhiteNoiseMiddleware', => delete this line
]

# ...

if os.environ.get('ENV') == 'PRODUCTION':
    # ...
    # Simplified static file serving.
    # https://warehouse.python.org/project/whitenoise/
    # STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' => delete this line

    # ...

Puis configurez Nginx ! Faites l'exercice et regardez ma solution. Petit conseil : utilisez une structure conditionnelle ! Regardez comment faire dans la documentation.

etc/nginx/sites-available/disquaire

server {
    # ...

    location /static {
        alias /home/celinems/disquaire/disquaire_project/staticfiles/;
    }

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://127.0.0.1:8000;
            break;
        }
    }
}

Retournez voir votre site : il fonctionne parfaitement bien !

Tous les fichiers sont bien servis par Nginx, c'est super !

Heu, non, ce n'est pas du tout super ! On a lancé le serveur de développement, tout le monde a accès à notre configuration !

Effectivement, cela ne va pas du tout ! Nous n'aurions jamais dû lancer le serveur de Django ainsi. La commande ./manage.py runserver lance un serveur de développement, loin d'être efficace en production et surtout non sécurisé !

Comment faire ? Voyons cela dans le prochain chapitre !

Example of certificate of achievement
Example of certificate of achievement