Howto Nginx
- Installation
- Configuration de base
- Gestion des droits
- VirtualHost
- Monitoring
- Les Websocket
- Optimisation
- SSL
- HTTP/2
- Cas pratiques
- RTMP
- Protocol PROXY
- FAQ
- Configuration en ligne
- Page personnalisée lors code erreur HTTP
- Appliquer des conditions sur des en-têtes
- Comment prononcer Nginx ?
- .htaccess ?
- Erreurs diverses
- Hash maps non prises en compte
- Bloquer l’acces au dépot Git
- Too many open files
- Signification des motifs de correspondance pour le bloc « location »
- Code 413 Request Entity Too Large
- if is evil
- Documentation : https://nginx.org/en/docs/
- Rôle Ansible : https://gitea.evolix.org/evolix/ansible-roles/src/branch/stable/nginx
- Statut de cette page : prod / bookworm
Nginx est un serveur HTTP léger, le deuxième plus utilisé sur le web derrière Apache.
Installation
# apt install nginx-full
$ /usr/sbin/nginx -V
nginx version: nginx/1.22.1
built with OpenSSL 3.0.8 7 Feb 2023 (running with OpenSSL 3.0.9 30 May 2023)
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 […]
# systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Fri 2023-07-28 21:43:35 CEST; 1s ago
Docs: man:nginx(8)
Process: 38051 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Process: 38052 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 38053 (nginx)
Tasks: 2 (limit: 2356)
Memory: 2.2M
CPU: 34ms
CGroup: /system.slice/nginx.service
├─38053 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
└─38054 "nginx: worker process"
Configuration de base
Fichiers de configuration :
/etc/nginx/
├── conf.d
├── fastcgi.conf
├── fastcgi_params
├── koi-utf
├── koi-win
├── mime.types
├── modules-available
├── modules-enabled
│ ├── 50-mod-http-auth-pam.conf -> /usr/share/nginx/modules-available/mod-http-auth-pam.conf
│ ├── 50-mod-http-dav-ext.conf -> /usr/share/nginx/modules-available/mod-http-dav-ext.conf
│ ├── 50-mod-http-echo.conf -> /usr/share/nginx/modules-available/mod-http-echo.conf
│ ├── 50-mod-http-geoip.conf -> /usr/share/nginx/modules-available/mod-http-geoip.conf
│ ├── 50-mod-http-image-filter.conf -> /usr/share/nginx/modules-available/mod-http-image-filter.conf
│ ├── 50-mod-http-subs-filter.conf -> /usr/share/nginx/modules-available/mod-http-subs-filter.conf
│ ├── 50-mod-http-upstream-fair.conf -> /usr/share/nginx/modules-available/mod-http-upstream-fair.conf
│ ├── 50-mod-http-xslt-filter.conf -> /usr/share/nginx/modules-available/mod-http-xslt-filter.conf
│ ├── 50-mod-mail.conf -> /usr/share/nginx/modules-available/mod-mail.conf
│ └── 50-mod-stream.conf -> /usr/share/nginx/modules-available/mod-stream.conf
├── nginx.conf
├── proxy_params
├── scgi_params
├── sites-available
│ └── default
├── sites-enabled
│ └── default -> /etc/nginx/sites-available/default
├── snippets
│ ├── fastcgi-php.conf
│ └── snakeoil.conf
├── uwsgi_params
└── win-utf
La configuration principale se fait dans le fichier
/etc/nginx/nginx.conf
qui inclut plusieurs fichiers séparés
:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
use epoll;
worker_connections 10240;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/dhparam.pem;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Le fichier /etc/nginx/conf.d/z-evolinux-defaults.conf
contient nos optimisations basiques :
server_tokens off;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
server_name_in_redirect off;
index index.html;
Le fichier nginx/snippets/evolinux_server_custom
contient notre configuration à inclure dans chaque bloc “server” :
location ~ /\.(inc|git|bak|env) {
# We don't want to let the client know a file exist on the server,
# so we return 404 "Not found" instead of 403 "Forbidden".
return 404;
}
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
:
allow 192.0.2.42;
Valider la configuration
Avant de redémarrer le serveur, vérifier que vous n’ayez pas introduit des erreurs de syntaxes dans la configuration :
# nginx -t -c /etc/nginx/nginx.conf
configuration file /etc/nginx/nginx.conf test is successful
Gestion des droits
Par défaut, Nginx est configuré pour se lancer avec l’utilisateur
www-data
et le groupe du même nom.
Les ressources web doivent donc être accessibles en lecture pour le
groupe www-data
.
De même, les fichiers ou répertoire (logs…) dans lesquels Nginx a
besoin d’écrire doivent être accessibles en écriture pour le groupe
www-data
.
Idéalement, on crée un compte Unix par vhost.
- Si l’utilisateur existe déjà, ajouter l’utilisateur
www-data
dans le groupe de l’utilisateur dédié :
# adduser www-data <USER_GROUP>
- Si l’utilisateur n’existe pas encore et qu’il sera dédié uniquement
au vhost, utiliser
www-data
comme groupe primaire :
# adduser --ingroup www-data <USER>
Note : adduser
doit avoir la configuration suivante
:
# grep -E '^DIR_MODE' /etc/adduser.conf
DIR_MODE=0750
À moins de lancer plusieurs instances de Nginx avec systemd, on ne
peut pas compartimenter des comptes web au niveau de Nginx, comme c’est
par exemple le cas avec le module Apache ITK (directive
AssignUserID
).
VirtualHost
De façon similaire à Apache, on peut avoir
plusieurs VirtualHost
, c’est-à-dire plusieurs sites sur un
même serveur HTTP.
Voici un exemple de VirtualHost via
/etc/nginx/sites-available/example
:
server {
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/ssl/certs/www.example.com.chain.pem;
ssl_certificate_key /etc/ssl/private/www.example.com.key;
server_name www.example.com example.com;
root /home/example/www;
location / {
try_files $uri $uri/ =404;
}
location /images/ {
root /home/example/images;
}
location ~ \.css$ {
root /home/example/css;
}
access_log /var/log/access.log;
access_log /var/log/example.access.log;
error_log /var/log/example.error.log;
}
Note : Dans cet exemple, il faut que /home/example/www
soit accessible à www-data
. Voir Gestion des droits
Directives location
Nginx examine d’abord les directives location
avec des
expressions régulières, puis les plus longues, qui sont évaluées avant
les plus courtes.
Dans l’exemple ci-dessus, Nginx vérifie d’abord si la ressource
demandée se termine par .css
puis si elle commence par
/images/
, puis au final la directive
location /
.
alias
Les alias permettent de faire servir du contenu qui ne serait pas stocké dans un répertoire servi par nginx (/var/www/nginx par exemple).
location /crossdomain.xml {
alias /foo/bar/fichier.xml;
}
Quelle différence entre la directive alias
et
root
?
alias
redirige la requête initiale sans le chemin
complet tandis que la directive root passe en paramètre le chemin
complet.
Exemple :
location /hello/ {
alias /spool/images/;
}
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
.
proxy_pass
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)
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
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
location / {
proxy_pass http://backend;
proxy_redirect http:// $scheme://;
}
La documentation de Nginx liste tous les paramètres utilisables dans ce contexte. Par exemple :
upstream backend {
server 127.0.0.1:8080;
}
[...]
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
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 fautproxy_http_version 1.1
etproxy_set_header Connection ""
.
Timeout du proxy_pass
Ce module propose plusieurs variables permettant de configurer des timeouts. Les plus utiles sont :
proxy_read_timeout
: timeout de la réception de la réponse du backend applicatif vers Nginx.proxy_send_timeout
: timeout d’envoi de la requête de Nginx vers le backend applicatif.
Les valeurs par défaut sont :
proxy_read_timeout 60s;
proxy_send_timeout 60s;
rewrite
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
On peut faire des ré-écritures basiques (moins puissant que les Rewrite Rules d’Apache), par exemple :
rewrite ^regex$ /vers-cette/uri.exemple.php {last,break,permanent,redirect};
real_ip_header
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é :
set_real_ip_from 192.0.2.10; # IP to trust
set_real_ip_from 10.0.0.0/24; # CIDR to trust
real_ip_recursive on;
real_ip_header X-Forwarded-For;
Cela permet ensuite d’appliquer ensuite des restrictions d’adresses IP par exemple.
Authentification HTTP
http://wiki.nginx.org/HttpAuthBasicModule
Pour configurer une authentification HTTP, on ajoutera les lignes
suivantes au sein d’une directive location
:
auth_basic "Restricted";
auth_basic_user_file /home/foo/.htpasswd;
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).
Ne s’applique pas aux IP connu
Admettons que l’on veut pas de l’authentification HTTP pour des IPs précises. On aura ces directives :
satisfy any;
allow X.X.X.X;
allow X.X.X.X;
deny all;
auth_basic "Restricted";
auth_basic_user_file /home/foo/.htpasswd;
Redirection https
server {
listen 80;
server_name www.example.com example.com;
#include /etc/nginx/snippets/letsencrypt.conf;
location / {
return 301 https://www.example.com$request_uri;
}
}
server {
listen 443 ssl;
server_name example.com;
return 301 https://www.example.com$request_uri;
[…]
}
server {
listen 443 ssl;
server_name www.example.com;
[…]
}
Ou globalement, de manière générale, on peut faire :
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
Si on vhost répondant à plusieurs domaines (plusieurs
server_name
) et qu’on ne veux pas forcer la redirection
vers l’un des domaines il faut utiliser la variable $host
plutot que $server_name
. Ce qui donne :
if ($scheme = http) {
return 301 https://$host$request_uri;
}
Si on utilise Let’s Encrypt, on ne souhaite pas faire de redirection pour les requêtes de challenge http :
server {
listen 80;
server_name www.example.com example.com;
location ~ /.well-known/acme-challenge {
alias /var/lib/letsencrypt/;
try_files $uri =404;
auth_basic off;
allow all;
}
location / {
return 301 https://www.example.com$request_uri;
}
}
Bloquer selon adresse IP
Le but est de bloquer par adresse IP et de rediriger vers une page « Vous êtes bloqués ».
# Blacklisting
geo $blacklist {
default 0;
192.0.2.42/32 1;
}
server {
[…]
# Blacklisting
if ($blacklist) {
rewrite ^ http://donthackmeplz.fr;
}
Fermer la connexion sans envoyer de réponse
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 :
location /search {
return 444;
}
Cross-domain pour les fonts
location ~* \.(eot|ttf|woff)$ {
add_header Access-Control-Allow-Origin *;
}
http_user_agent
On peut définir des actions en fonction du User-Agent :
if ($http_user_agent ~* (DotBot|Cliqzbot|AhrefsBot|SemrushBot)) {
return 404;
}
Note : Si l’on doit bloquer un User-Agent avec des espaces dans son nom, une solution est d’échapper les espaces :
if ($http_user_agent ~* (DotBot|Cliqzbot|AhrefsBot|SemrushBot|Go\ 1\.1\ package\ http)) { return 404; }
more_set_headers
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 :
more_set_headers 'Server: ';
more_set_headers 'Server: My Server v42';
PHP-FPM
Vous devez installer PHP-FPM et configurer un pool FPM pour être accessible sur une socket du type :
[foo]
listen = /run/php/php-fpm.foo.sock
listen.owner = www-data
listen.group = www-data
user = foo
group = foo
et enfin configurer un VirtualHost incluant une directive du type :
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.foo.sock;
include snippets/fastcgi-php.conf;
}
Nginx apporte un snippet de configuration dans
/etc/nginx/snippets/fastcgi-php.conf
qui permet de
préconfigurer les variables nécessaires pour la communication fastcgi
entre Nginx et FPM
Plus de détails sur Configuration FPM avec Nginx.
FPM et Alias Nginx
Le réglage par défaut de fast-cgi dans Nginx ne colle pas très bien
entre l’utilisation de la directive alias
dans un bloc
location
. On obitient une erreur
File not found.
venant de FPM, car la variable
SCRIPT_FILENAME
est donnée relativement au
root
du vhost.
Une alternative possible est de définir le bloc location
de la manière suivante, en redéfinissant l’appel à FPM avec la bonne
valeur de SCRIPT_FILENAME
location /phpmyadmin-3615/ {
alias /usr/share/phpmyadmin/;
index index.php;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
Mode maintenance
Il est possible de déclencher très facilement un mode maintenance avec une page spécifique.
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.
location / {
if (-f /home/example/www/maintenance.html) { return 503; }
[…]
}
On personnalise alors la page présentée en cas d’erreur 503, en
servant cette même page maintenance.html
error_page 503 @maintenance;
location @maintenance {
root /home/example/www;
rewrite ^(.*)$ /maintenance.html break;
}
En situation normale, on peut avoir le fichier
/home/example/www/_maintenance.html
.
Pour activer le mode maintenance (pas besoin de recharger Nginx) :
$ mv /home/example/www/{_,}maintenance.html
Pour désactiver le mode maintenance (pas besoin de recharger Nginx) :
$ mv /home/example/www/{,_}maintenance.html
Favicon en cache
Pour favoriser la mise en cache des “favicon” il est possible d’ajouter cet extrait dans un bloc “server” :
server {
[…]
location ~* favicon\.(ico|gif|png)$ {
expires 30d;
add_header Pragma public;
add_header Cache-Control public;
access_log off;
}
[…]
}
Les fichiers favicon.ico, favicon.png et favicon.gif seront candidats à la mise en cache pendant 30 jours et aucun log d’accès ne sera inscrit.
GZIP
Afin d’activer la compression GZIP, nous conseillons d’ajouter la configuration suivante :
gzip on;
#gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/javascript application/ecmascript application/xml application/xml+rss application/json image/svg+xml
Note : il faut bien enlever text/html
de la liste gzip_types
car ça donne une erreur pour doublon
de valeur.
Monitoring
log2mail
Pour être alerté en cas d’erreur grave, on ajoute la configuration suivante au logiciel log2mail :
file = /var/log/nginx/error.log
pattern = "[emerg]"
mailto = alert@example.com
# adduser log2mail adm
# servicectl restart log2mail
apachetop
apachetop peut servir aussi pour Nginx, voir HowtoApache#apachetop
Munin
Ajouter dans la configuration Nginx :
location /nginx_status_NNNN {
stub_status on;
allow 127.0.0.1;
allow 192.0.2.42;
deny all;
}
Puis dans la configuration Munin :
[nginx*]
env.url http://127.0.0.1/nginx_status_NNNN
On peut ainsi activer les plugins nginx_request et nginx_status :
# cd /etc/munin/plugins
# ln -s /usr/share/munin/plugins/nginx_request nginx_request
# ln -s /usr/share/munin/plugins/nginx_status nginx_status
Les Websocket
Ce protocole permet aux applications qui prennent en charge la communication bidirectionnelle en temps réel entre les clients et les serveurs.
Dans un vhost gérant l’application, il y a besoin de rajouter une map en dehors du block server pour que les en-têtes de connections soient correctement défini :
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
l’ajout de ces directives sont nécessaires :
server {
[...]
location/ {
[...]
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
Optimisation
Worker Connections et Keep Alive
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 consiste à créer un override systemd de l’unité nginx.
# mkdir -p /lib/systemd/system/nginx.service.d
# cat << EOT > /lib/systemd/system/nginx.service.d/limitnofile
[Service]
LimitNOFILE=16384
EOT
# systemctl daemon-reload
### Mettre la directive worker_rlimit_nofile 16384; dans les premières lignes de nginx.conf
# systemctl restart nginx
Limiter le taux de requêtes par IP
On peut définir un « taux » maximum de connexions par IP, ainsi qu’une queue pour les requêtes qui dépassent cette limite.
Doc : https://www.nginx.com/blog/rate-limiting-nginx/
Ajouter dans /etc/nginx/conf.d/zzz-evolinux-custom.conf
:
# Define the parameters for rate limitation (10Mo cache memory, max 1 request/100ms for an IP)
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
Ajouter dans le bloc server
des vhosts concernés :
# Define the rate limit, queue up the resquests to 20 if the rate limit is exceeded, nodelay answers immediatement the requests in the rate limit
limit_req zone=mylimit burst=20 nodelay;
Attention : En fonction du site, une requête dans le navigateur peut impliquer des dizaines de requêtes au serveur (pour le chargement des ressources). Le souci est que, par exemple, limiter à 10 requêtes par seconde et par IP, permet quand même à un bot agressif de faire 36 000 requêtes par heure… Il est souvent préférable d’utiliser Fail2Ban.
Vous obtiendrez dans le error.log des messages du type :
[error] 23699#23699: *148813 limiting requests, excess: 2.744 by zone "mylimit", client: 192.0.2.42...
SSL
listen 0.0.0.0:443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/ssl/certs/ssl.example.com.crt;
ssl_certificate_key /etc/ssl/private/ssl.example.com.key;
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 :
# cd /tmp
# wget https://www.startssl.com/certs/class1/sha2/pem/sub.class1.server.sha2.ca.pem
# cat sub.class1.server.sha2.ca.pem >> /etc/ssl/certs/ssl.example.com.crt
Pour une configuration plus avancée, voir HowtoSSL ou HowtoLetsEncrypt
HTTP/2
En version 1.10, la plupart des fonctionnalités du protocole est supportée par Nginx.
Note : une version limitée du protocole était déjà supportée depuis Nginx 1.9.5.
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é :
listen 0.0.0.0:443 ssl http2;
Cas pratiques
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
}
[...]
location / {
proxy_pass http://varnish_or_direct_backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
RTMP
https://trac.ffmpeg.org/wiki/StreamingGuide https://github.com/arut/nginx-rtmp-module/wiki/Directives
# apt install libnginx-mod-rtmp
Configuration à ajouter à nginx.conf :
rtmp {
server {
listen 1935;
application live {
live on;
}
}
}
Publication d’un flux RTMP :
$ ffmpeg -thread_queue_size 0 -f v4l2 -i /dev/video0 -f flv "rtmp://127.0.0.1/live/foo"
Lecture d’un flux :
$ ffplay -probesize 32 -sync ext "rtmp://127.0.0.1/live/foo"
Protocol PROXY
L’utilisation du protocol PROXY permet de faciliter la communication et la traçabilité lorsque des proxy sont impliqués.
À consulter :
- présentation générale du protocol
- doc complète sur la mise en œuvre pour Nginx.
Nginx en aval
Il faut écouter en acceptant le protocol PROXY, et indiquer la/les IP des proxy de confiance :
http {
#...
server {
listen 80 proxy_protocol;
listen 443 ssl proxy_protocol;
#...
set_real_ip_from 192.168.1.0/32;
real_ip_header proxy_protocol;
}
}
Nginx en amont
TODO: aire une synthèse de la doc officielle
FAQ
Configuration en ligne
Un site permet de générer sa configuration Nginx en ligne : https://nginxconfig.io/
Page personnalisée lors code erreur HTTP
On peut avoir une page personnalisée selon le code d’erreur HTTP renvoyé.
location /YYYYYY/ {
alias /var/wwwerror/;
index page.html;
}
error_page 403 /YYYYYY/;
Appliquer des conditions sur des en-têtes
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.
Cela peut avir des comportements inattendus.
Comment prononcer Nginx ?
C’est la première question de la FAQ officielle du projet. Pour les francophones, voilà notre astuce :
- D’abord le N se prononce tout seul, comme dans « haine ».
- Puis gin, comme dans « imagine », ou « j’ai enfilé mon jean ».
- Et enfin x, comme dans « j’habite à Aix ».
.htaccess ?
Nginx ne gère pas les fichiers .htaccess
. Si vous devez
utiliser des fichiers .htaccess
, utilisez Apache.
Erreurs diverses
https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
Hash maps non prises en compte
Il est posisble de créer des “hash map” (cf. ngx_http_map_module) 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.
Bloquer l’acces au dépot Git
Pour bloquer l’acces à aux données d’un dépot Git, dans un dossier
servit par Nginx, il faut rajouter le code suivant dans un contexte
server
, location
ou if
:
location ~ /\.git {
return 404;
}
Too many open files
Si des erreurs “Too many open files” sont retournées par nginx il faut augmenter le nombre maximum de descripteur.
Signification des motifs de correspondance pour le bloc « location »
La documentation officielle présente les modificateurs associés aux motifs de correspondance des chemins pour les URLs.
- aucun : sans modificateur dans un bloc location, l’URI indiquée sera mise en correspondance avec le début de l’URI demandée.
- = : le signe égal est utilisé pour faire correspondre exactement l’URI indiquée et l’URI demandée.
- ~ : le tilde est utilisé pour faire correspondre à l’aide d’une expression rationnelle non sensible à la casse l’URI indiquée et l’URI demandée.
- ~* : le tilde suivi d’une astérisque est utilisé pour faire correspondre à l’aide d’une expression rationnelle sensible à la casse l’URI indiquée et l’URI demandée.
- ^~ : le caret suivi d’un tilde est utilisé pour faire la plus grande correspondance sans expression rationnelle entre l’URI indiquée et l’URI demandée. Si l’URI demandée correspond, aucune autre tentative de correspondance n’aura lieu.
Code 413 Request Entity Too Large
Les logs de Nginx devraient indiquer :
client intended to send too large body: 2718281 bytes
. Il
faut ajuster la
directive client_max_body_size
. Par exemple :
server {
[...]
client_max_body_size 4m;
}
if is evil
Nginx conseille de minimiser l’utilisation de if
autant
que possible :
https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/