Le fichier `/etc/nginx/snippets/ipaddr_whitelist` centralise les adresses IP privilégiées, on peut ainsi utiliser `include /etc/nginx/snippets/ipaddr_whitelist;` à différents endroits dans la configuration de Nginx sans dupliquer ces adresses :
Avec `alias`, pour une requête sur `/hello/world.png` Nginx renverra le contenu de `/spool/images/world.png` tandis qu'avec la directive `root`, elle renverra le contenu de `/spool/images/hello/world.png`.
Nginx peut aussi agir comme Reverse Proxy. On utilisera alors la directive **proxy_pass** pour définir le serveur vers lequel la requête est envoyée. On peut aussi définir des headers qui seront ajoutés à la requête quand elle est transmise (Notamment, l'IP du visiteur, car le serveur derrière le proxy ne peut voir l'IP de celui-ci)
Il est aussi possible de déplacer les infos sur l'upstream vers un bloc de configuration du même nom en dehors du bloc *server*. Cela peut permettre notamment de spécifier plusieurs backends (cas load-balancer) ou un backend de secours.
Si upstream ne prends pas en compte ces header, il est possible de modifier les redirections qu'il renvoit pour éviter qu'il ne redirige d'une URL avec du HTTPS vers une sans, en utilisant `proxy_redirect`
> Il est important de noter que pour que la directive `keepalive` dans la définition de l'upstream soit utile il faut configurer les connexions proxy correctement. Notamment, pour un proxy http, il faut `proxy_http_version 1.1` et `proxy_set_header Connection ""`.
Si les requêtes viennent d'un proxy HTTP (Varnish par exemple), il faut substituer l'adresse IP d'origine par celle contenue dans le header `X-Forwarded-for`.
Cela se fait ainsi en s'assurant d'avoir le paquet `nginx-extras` installé :
Attention, si l'on ne souhaite protéger tout le site (location /), il faudra se méfier et bien ajuster la configuration pour s'assurer que tous les fichiers sont protégés (notamment les fichiers PHP par exemple).
Le fichier `.htpasswd` étant généré avec l'utilitaire *htpasswd* (comme pour Apache). Bien vérifier les droits en lecture pour l'utilisateur qui fait tourner Nginx (_www-data_ en général).
Dans certains cas, pour protéger le serveur par exemple, on peut être amené à vouloir fermer directement certaines connexions, sans même donner de réponse. Cela peut servir notamment lors d'un DDoS pour bloquer certaines parties d'un site qui peuvent être lourdes (comme une page de recherche) ou certains clients que l'on juge malicieux.
Il suffit alors d'utiliser `return 444`. Exemple :
Si l'on veut manipuler les headers HTTP, on s'assure d'avoir le paquet `nginx-extras` installé, puis on peut utiliser la directive `more_set_headers`. Exemples :
En plaçant cette ligne dans votre bloc `location`, il suffira que le fichier `maintenance.html` existe pour que Nginx renvoie systématiquement une erreur 503.
Il s'agit du nombre de connexions qu'un _worker process_ peut gérer. Le nombre de connexions multiplié par le nombre de _worker processes_ détermine le nombre total de connexions qu'il est possible de gérer simultanément. Cependant un autre paramètre intervient, il s'agit du _keep-alive time-out_ qui détermine la durée d'une connexion d'un client : lorsqu'un client se connecte au site, la connexion établie n'est pas fermée tout de suite, cela permet de faire passer plusieurs requêtes dans une seule connexion. La connexion sera fermée après le timeout. Il faut donc ajuster ces 2 paramètres en fonction de votre site (astuce : surveiller ses courbes Munin puis ajuster ces paramètres). Une configuration classique est de mettre 10240 en `worker_connections` et entre 10 et 20 secondes pour `keepalive_timeout`.
~~~
events {
worker_connections 10240;
}
http {
keepalive_timeout 15;
[…]
~~~
Si l'on souhaite désactiver complètement le Keep Alive, on mettra `keepalive_timeout 0;`
### Diminuer les I/O
Afin d'éviter un goulot d'étranglement sur les I/O, on peut via certains paramètres réduire les accès disques, et donc optimiser l'I/O pour servir le contenu web.
#### Access Logs
À chaque requête nginx écrit dans le fichier d'access logs. Plus il y a de requêtes plus cela est coûteux en accès disque. Il est donc recommandé d'écrire les access logs dans la mémoire RAM (via une ramdisk par exemple), et de faire un logrotate sur le disque une fois une certaine taille atteinte.
#### Error Logs
Ne pas oublier de désactiver le mode verbose/debug lorsque le serveur est en production…
#### Open File Cache
Détermine le nombre de fichiers ouverts à mettre en cache.
#### Buffers
Si les tampons mémoire ne sont pas assez grands, nginx va devoir écrire dans des tampons temporaires sur le disque dur ce qui augmente les accès disques.
La directive `client_body_buffer_size` détermine la taille du buffer du champ `body` d'une requête d'un client. Selon cas il peut être intéressant de l'accorder avec une taille en concordance avec vos formulaires, typiquement si vous avez des gros formulaires avec des données à uploader il faudra augmenter le buffer.
La directive `fastcgi_buffers` et `proxy_buffers` sont les buffers associés à php/cgi/… Le concept est le même que le buffer pour les clients. Si les tampons sont trop petits, les données vont être temporairement écrite sur le disque.
#### Activer la compression gzip
Cette directive permet au visiteur de télécharger des données compressées par le serveur, permettant d'alléger la bande passante. *Il est recommandé de mettre `gzip_comp_level` à 4 ou 5*.
On peut aussi servir directement des fichiers déjà compressés : voir <http://wiki.nginx.org/HttpGzipStaticModule>
### Augmenter le nombre maximum de descripteur de fichiers
L'[astuce](https://www.masv.io/boost-nginx-connection-limits/) consiste à créer un override systemd de l'unité nginx.
Attention, `ssl_certificate` doit contenir toute la chaîne de certification, donc il sera nécessaire de concaténer les certificats. Par exemple, on ajoutera le certificat intermédiaire via :
Il faut alors activer le protocole dans la directive `listen`. Sachant que les navigateurs courants ne supportent HTTP/2 que pour des connexions sécurisées, on activera toujours le SSL/TLS. Il est également nécessaire de désactiver le protocole SPDY s'il était utilisé :
### Fail-over d'un backend principal pour proxy_pass
Dans certains cas, on peut utiliser *Nginx* pour faire la décharge SSL/TLS avant d'envoyer les requêtes vers un Varnish avec proxy_pass.
Pour ne pas perturber le site lors d'un redémarrage ou rechargement de Varnish, on peut par exemple configurer *Nginx* pour renvoyer directement les requêtes vers le service caché par Varnish si le service de cache n'est pas disponible.
Il suffit d'utiliser le mot clé `backup` dans la définition du serveur dans l'objet `upstream` :
~~~
upstream varnish_or_direct_backend {
server 127.0.0.1:8080; # Varnish
server 192.0.2.2:8081 backup; # Service caché par Varnish
Il est possible de configurer des comportements conditionnés par le contexte d'une requête.
Voici quelques exemples :
~~~
# rejetter toutes les méthodes autres que POST
if ($request_method != "POST" ) {
return 405;
}
# rejetter les requêtes qui n'ont pas une valeur spécifique pour un en-tête personnalisé
# NB : les variables "$http_x_" sont automatiquement remplies avec les en-têtes personnalisés.
if ($http_x_requested_with != "XMLHttpRequest" ) {
return 403;
}
# rejeter les requêtes qui ne sont pas du JSON
if ($content_type != "application/json") {
return 403;
}
~~~
Attention toutefois à l'utilisation de `if` dans un bloc `location` : [IfIsEvil](https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/). Cela peut avir des comportements inattendus.
C'est la première question de la [FAQ officielle](https://www.nginx.com/resources/wiki/community/faq/#how-do-you-pronounce-nginx) du projet. Pour les francophones, voilà notre astuce :
Il est posisble de créer des "hash map" (cf. [ngx_http_map_module](http://nginx.org/en/docs/http/ngx_http_map_module.html)) pour facilement cérer des variables utilisables dans des blocks, des logs…
Sauf que ces maps ne sont pas restreintes à un bloc serveur (VHost), mais appliquées à tout le bloc http. Il ne faut donc pas donner le même nom à 2 maps, au risque d'avoir des conflits difficiles à débugger.