tcp_nodelay force l’envoi immédiat des données contenues dans la socket, quelle que soit la taille du paquet.
tcp_nopush fait exactement le contraire de tcp_nodelay, il force à n’envoyer que des paquets ayant atteint la MSS, qui est égale au MTU moins les 40 octets d’en-tête.
sendfile force l’utilisation de l’appel système sendfile(2) pour tout ce qui concerne l’envoi de fichiers. Très performant pour les fichiers statiques stockés localement.
# par défaut
error_log stderr error; # écrit dans le journal à partir du niveau error
server {
# définir un fichier particulier pour le log
error_log /var/log/nginx/mon_site_error.log;
Il n'est pas possible de modifier le format du log d'erreurs:
YYYY/MM/DD HH:MM:SS [LEVEL] PID#TID: *CID MESSAGE
PID: logging process id, TID: thread id, CID: connection id
Mais on peut choisir le niveau de log: debug, info, notice, warn, error, crit, alert, emerg
# par défaut
access_log /var/log/nginx/access.log combined; # écrit dans le fichier access.log au format combined# format combined
log_format combined '$remote_addr - $remote_user [$time_local] ''"$request" $status $body_bytes_sent ''"$http_referer" "$http_user_agent"';
server {
# définir un fichier particulier pour le log
access_log /var/log/nginx/mon_site_access.log;
# désactiver le log access
access_log off;
# ne pas logguer les erreurs de fichiers non trouvés
log_not_found off;
# compresser le log
access_log /path/to/log.gz combined gzip=9 flush=5m;
# By default, the buffer size is equal to 64K bytes, and the compression level is set to 1.# The compression level can be set between 1 (fastest, less compression) and 9 (slowest, best compression).
« nginx -V » pour obtenir les valeurs par défaut des variables définies lors de la compilation.
--http-log-path=/var/log/nginx/access.log
--error-log-path=stderr
Les conditions ne fonctionnent qu'à partir de la version 1.7: invalid parameter "if=loggable"
log_format
/etc/nginx/nginx.conf
# formats prédéfinits
http {
log_format combined '$remote_addr - $remote_user [$time_local] ''"$request" $status $body_bytes_sent ''"$http_referer" "$http_user_agent"';
# combined + $http_x_forwarded_for
log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';
# pour un log multi serveur car il contient $server_name
log_format global '[$time_local] $status $server_name ''$remote_addr "$request" - ''"$http_referer" - "$http_user_agent"';
$time_local
heure à laquelle la requête a été trairée
$status
code de retour: 200 Ok, 403 Forbidden, 404 Not Found
$remote_addr
adresse ip du client
$http_referer
url de la page précédente
$request
la requête
$http_user_agent
information sur le client: logiciel, OS
$request_time
temps de traitement de la requête
$server_name
le nom du serveur correspondant à la requête
$http_x_forwarded_for
vraie adresse ip du client provenant d'un proxy HTTP ou d'un répartiteur de charge
# les ip locales 192.168.0.x ne seront pas loguées# map doit être définit dans http
map $remote_addr$loggable {
~^192\.168\.0\. 0; 0; # 0 → ne pas logguer
default 1;
}
access_log /path/to/access.log combined if=$loggable;
# utiliser plusieurs paramètres en les concaténant en un seul string# les tests de correspondance se font donc sur ce string concaténé
map $remote_addr$request$loggable {
~^192\.168\.0\. 0; # ne pas logguer les ip 192.168.0.x"~*GET /wiki/" 1; # logguer les requêtes qui contiennent GET /wiki/
default 0; # ne pas logguer le reste
}
Buffer limitations
/etc/nginx/nginx.conf
# default is 8k or 16k
client_body_buffer_size 1K;
client_header_buffer_size 1k;
# If size is greater the given one, then the client gets the error "Request Entity Too Large" (413).# Increase this when you are getting file uploads via the POST method.
client_max_body_size 1k;
# Default: large_client_header_buffers 4 8k;# Context: http, server
large_client_header_buffers 8 32k;
# Default: proxy_buffers 8 4k|8k;# Context: http, server, location
proxy_buffers 8 32k;
# Default: proxy_buffer_size 4k|8k;# Context: http, server, location
proxy_buffer_size 64k;
Timeout
/etc/nginx/nginx.conf
# The default is 60
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
Permet de modifier la configuration en fonction de la requête.
/etc/nginx/nginx.conf
server {
# correspond seulement à la requête /
location = / { }
# emplacement par défaut# si aucun autre emplacement ne correspond, c'est celui-ci qui sera utilisé
location / { }
# correspond aux requêtes commençant par /mon_dossier/# mais la recherche de correspondances continue
location /mon_dossier/ { }
# correspond aux requêtes commençant par /mon_dossier2/# la recherche de correspondances s'arrête ici: ^~
location ^~ /mon_dossier2/ { }
# expressions rationnelles: ~ sensible à la casse ~* insensible à la casse
location ~* \.(gif|jpg|jpeg)$ { }
location ~ /(dossier1|dossier2)/ { }
# les locations peuvent s'imbriquer
location /dossier/ {
location ~* \.png$ { }
}
Ordre de vérification des correspondances:
Directives avec le préfixe « = ». S'il y a correspondance la recherche s'arrête là.
Directives avec une chaîne de caractères. La recherche continue sauf si le prefix « ^~ » a été utilisé. En cas de correspondances multiples c'est la directive la plus longue qui l'emporte.
Directives avec une expression rationnelle dans l'ordre dans lesquelles elles ont été définies. S'il n'y a pas de correspondance, c'est la correspondance avec la directive n°2 la plus longue qui est utilisée.
^~ ne fonctionne pas avec les regex.
Les arguments (arg=value) ne sont pas pris en compte pour la correspondance.
# interdit l'accès au site à tous sauf à 192.168.0.0/24
allow 192.168.0.0/24;
deny all;
# interdit l'accès aux pages dont l'url contient Spécial à tous sauf à 192.168.0.1
location ~ Spécial {
allow 192.168.0.1;
deny all;
}
# utilisation d'un fichier de configuration contenant toutes les ip à exclure
include /etc/nginx/blacklist;
/etc/nginx/blacklist
deny x.x.x.x;
deny y.y.y.y;
Les autorisations sont analysées dans l'ordre, la première correspondance est appliquée.
Il faut donc les écrire des plus spécifiques aux plus globales.
En cas d'interdiction le serveur envoie le signal d'erreur 403 Forbidden
Test si $uri existe, si ce n'est pas le cas, test si uri/fichier1.html existe puis $uri/fichier2.html
Si un des fichiers existe, il est utilisé. Si aucun fichier de la liste n'existe, une redirection interne est faite vers le dernier.
/etc/nginx/nginx.conf
try_files$uri$uri/fichier1.html $uri/fichier2.html;
# Si aucun fichier de la liste n'existe, redirection vers la location @othertry_files$uri$uri/fichier1.html $uri/fichier2.html @other;
location@other { }
# génère l'erreur 404 si aucun fichier de la liste n'existetry_files$uri$uri/fichier1.html $uri/fichier2.html =404;
root /srv/http/mon_site;
location ^~ /autre_dossier {
alias /un/autre/dossier;
# la requête /autre_dossier/fichier.html reverra le fichier /un/autre/dossier/fichier.html# alors que la requête /dossier/fichier.html reverra le fichier /srv/http/mon_site/fichier.html
}
# Si la location correspond à la fin de l'alias, il est préférable d'utiliser la directive root
location ^~ /dossier {
alias /data/dossier;
}
location ^~ /dossier {
root /data;
}
Permet de définir les pages à afficher en cas d'erreurs.
/etc/nginx/nginx.conf
# redirige vers la page 404.html en cas d'erreur 404
error_page 404 /404.html;
# redirige vers la page 404.html en cas d'erreur 404 et retourne le code 200 au lieu du code 404
error_page 404 =200 /404.html;
# pourl'erreur 403 (forbidden), il faut en plus authoriser l'accès à la page d'erreur
error_page 403 /error403.html;
location = /error403.html {
# internal: page error403.html accessible seulement via ce mécanisme et pas directement
internal;
allow all;
}
Les hôtes virtuels de NGINX sont appelés blocs serveur.
/etc/nginx/nginx.conf
http {
# hôte virtuel site1
server {
server_name site1;
}
# hôte virtuel site2 ou alias2 ou *.domain.com ou une expression rationnelle
server {
server_name site2 alias2 *.domain.com ~^www\d+\.example\.com$;
}
# hôte virtuel par défaut# si aucune autre correspondance n'a été faite, c'est cet hôte qui est utilisé
server {
listen 80 default_server;
index index.html;
root /usr/share/nginx/html;
}
# génération de la ligne a ajouter au fichier de mots de passe (/etc/nginx/.htpasswd)printf"USER:$(openssl passwd -apr1)\n" >> /etc/nginx/.htpasswd
# -apr1 → MD5-based password algorithm, Apache variant
# création du fichier .htpasswd et ajout de l'utilisateur user_name
htpasswd -c /etc/nginx/.htpasswd user_name
# ajout d'autres utilisateur une fois le fichier créé
htpasswd /etc/nginx/.htpasswd user_name
# afficher l'utilisateur et le mot de passe haché dans la console
htpasswd -n user_name
Sécurité
Par défaut, c'est l’algorithme MD5 qui est utilisé pour encrypter les mots de passe. Il utilise un grain de sel (salt).
L’algorithme SHA (-s) n'utilise pas de grain de sel (salt).
L'algorithme bcrypt (-B) peut être encrypté avec l'option -C. Le désencryptage prend du temps de calcul.
# définition de la zone mémoire partagée, utilisée pour partager le compteur associé à la clé de la zone mémoire# limit_conn_zone CLÉ zone=NOM:TAILLE;
limit_conn_zone $binary_remote_addr zone=addr:10m;
# définit la limitation du nombre de connexions simultanées
limit_conn addr 1;
$binary_remote_addr → adresse IP du client. Permet de définir une limitation du nombres de connexions simultanées par client (adresse IP).
$server_name → nom du serveur. Permet de définir une limitation du nombres de connexions simultanées par serveur.
Permet de limiter le nombre de requêtes par seconde provenant d'une même ip, et ainsi de se protéger contre le flood / DoS.
/etc/nginx/nginx.conf
# créé une zone de 10 megabyte appelée « flood »# elle enregistrera le nombre de requêtes par clé,# ici $binary_remote_addr (adresse ip du client au format binaire pour économiser de l'espace mémoire)# 1r/s → 1 requête par secondes ; 30r/m → 30 requêtes par minutes
limit_req_zone $binary_remote_addr zone=flood:10m rate=1r/s;
# applique la limitation de requête# si le nombre de requêtes dépasse le ratio# les requêtes suivantes sont mise en attente dans la limite de burst (par défaut à 0)# au delà de burst les requêtes sont terminées avec le code d'erreur 503 (Service Temporarily Unavailable)
limit_req zone=flood burst=5;
# l'option nodelay permet de traiter les requêtes burst sans délai (plus de respect du ratio)# rate=5r/s équivalent à rate=1r/s burst=4 nodelay# définit le status à envoyer au client lorsqu'on termine la requête (503 par défaut)
limit_req_status 444;
# 444 code spécifique à nginx fermant la connexion et n'envoyant pas de réponse au client
Exemple:
limit_req_zone $binary_remote_addr zone=flood:10m rate=1r/s;
limit_req zone=flood burst=2 nodelay;
Envoie de 3 requêtes par secondes pendant 3 secondes
Req.# | Time (sec) | Response
1 0 200 OK rate=1r/s
2 0 200 OK burst +1=1
3 0 200 OK burst +1=2
1 burst -1=1
4 1 200 OK rate=1r/s
5 1 200 OK burst +1=2
6 1 503 burst=2 requête rejetée
2 burst -1=1
7 2 200 OK rate=1r/s
8 2 200 OK burst +1=2
9 2 503 burst=2 requête rejetée
# hsts, 31536000 s = 1 an
add_header Strict-Transport-Security "max-age=31536000";
# upgrade-insecure-requests → ensures that any HTTP assets are loaded using HTTPS
add_header Content-Security-Policy "upgrade-insecure-requests";
# hide the server version
server_tokens off;
# By preventing a browser from framing your site you can defend against attacks like clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# blocks the response if it detects a cross-site script.
add_header X-Xss-Protection "1; mode=block" always;
# support de Forward Secrecy (défaut: HIGH:!aNULL:!MD5)
ssl_ciphers "HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers On;
# Diffie-Hellman pour TLS
ssl_dhparam /path/dhparams.pem;
# fichier à générer avec: openssl dhparam -out dhparams.pem 2048# performances
ssl_stapling on;
ssl_session_cache shared:SSL:10m;
/etc/uwsgi/mysite.ini
; masquer le header X-Powered-By PHP/x.x.xphp-set = expose_php=Off
# choisir le dossier qui contiendra le certificatcd /etc/ssl/private
# créer la clé privée# nombre de bits : 2048 ou 4096
openssl genrsa -out server.key 4096
chmod 400 server.key
# créer le Certificate Signing Request (CSR)
openssl req -new -sha512 -key server.key -out server.csr
# Common Name doit correspondre au nom d'hôte (serveur.domaine.fr ou *.domaine.fr)# The "challenge password" is basically a shared-secret nonce between you and the SSL issuer, embedded in the CSR,# which the issuer may use to authenticate you should that ever be needed.# par défaut sha1 est utilisé# signer le certificat
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Configuration
/etc/nginx/nginx.conf
# redirection vers https
server {
server_name site.domaine.fr;
listen 80;
return 301 https://$server_name$request_uri;
}
server {
server_name site.domaine.fr;
listen 443 ssl;
ssl_certificate /etc/ssl/private/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
}
Découper le fichier de configuration
/etc/nginx/nginx.conf
include /etc/nginx/servers/*.conf;
/etc/nginx/servers/serveur1.conf
server {
listen 80;
server_name serveur1.mon-domaine.fr;
root /srv/http/serveur1;
index index.php;
include /etc/nginx/php_files.conf;
}
location ~ \.php5?$ {
# par défaut à 60s
uwsgi_read_timeout 90;
PHP
php-fpm
# installation
sudo pacman -S php-fpm
# démarrage du service
sudo systemctl start php-fpm
# démarrer php-fpm au démarrage du système
sudo systemctl enable php-fpm
/etc/nginx/nginx.conf
server {
listen 80;
server_name myserver;
root /srv/http/myserverfolder;
index index.html index.htm index.php;
location ~ \.php$ {
# test si le fichier php existe, sinon affiche l'erreur 404 au lieu du message "File not found."
try_files $uri =404;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
include /etc/nginx/fastcgi.conf;
# augmente le temps d'attente d'une réponse, par défaut à 60s
fastcgi_read_timeout 300;
}
}
Erreurs
502 Bad Gateway
php-fpm n'est pas démarré
504 Gateway Time-out
un service uwsgi pointe vers le même dossier
PhpStorm debug le service
log
Ne semble pas marcher.
/etc/php/php-fpm.d/www.conf
php_admin_value[error_log] = /var/log/fpm-php.www.log
php_admin_flag[log_errors] = on
# créer le fichier de log avec les bons droitstouch /var/log/fpm-php.www.log
chmod 777 /var/log/fpm-php.www.log
nginx gère l'url http://mon.site/image.gif/somefilename.php de cette façon:
comme l'url se termine par php, elle est transmise au gestionnaire de FastCGI PHP
PHP examine le path, trouve le fichier image.gif, et stocke /somefilename.php dans $_SERVER['PATH_INFO'], puis execute le contenu du fichier GIF comme du PHP. Comme les formats d'images peuvent contenir un contenu arbitraire. Il est possible qu'une image contiennent du code PHP malveillant.
Solutions:
cgi.fix_pathinfo=1 dans le fichier /etc/php/php.ini. Pose problème avec Wordpress.
try_files $uri =404; dans le bloc location du fichier /etc/nginx/nginx.conf. Fonctionne si nginx et le gestionnaire de script FastCGI PHP sont sur le même serveur.
Ajoutez un bloc location qui détecte les mauvaises URL.
Exclure explicitement les urls d'upload du block location.
Ne pas stocker sur le même serveur les fichiers uploadés et le gestionnaire de script FastCGI PHP.
L'utilisation de PHP_ADMIN_VALUE pose problème: une fois que le serveur contenant la directive est atteint la modification de la configuration PHP se propage à tous les serveur.