Configuration
 |
Le user et le group par défaut est http. |
Idéalement égal au nombre de processeurs.
|
nproc
grep -c ^processor /proc/cpuinfo
|
pid
Définit dans quel fichier le Process Id du serveur Nginx est stocké.
Par défaut /run/nginx.pid
Définit le nombre maximum de connexions simultanées qu'un worker process peut ouvrir.
- 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.
Temps en secondes pendant lequel la connexion restera ouverte.
Zipper les réponses.
/etc/nginx/nginx.conf
|
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types application/javascript image/svg+xml text/css;
|
Configuration du bloc server
Définit l'adresse et le port qui seront écoutés.
/etc/nginx/nginx.conf
|
listen 80 default_server;
|
Détermine quel bloc server sera utilisé en fonction de la requête.
Ordre de priorité:
- exact name
- longest wildcard name starting with an asterisk, e.g. “*.example.org”
- longest wildcard name ending with an asterisk, e.g. “mail.*”
- first matching regular expression (in order of appearance in a configuration file)
 |
Si aucun server_name ne correspond c'est le serveur possédant l'instruction listen 80 default_server qui sera utilisé, sinon le premier serveur. |
How nginx processes a request
Définit le chemin le dossier racine pour les requêtes.
Un root différent peut être définit pour chaque location.
 |
Si le chemin contient des espaces l'encadrer avec des guillemets simple. |
Définit les fichiers à utiliser lorsque la requête se termine par /.
Définit l'encodage de caractères par défaut pour les types text/plain or text/html.
Cette définition écrase celle spécifiée dans la balise meta.
/etc/nginx/nginx.conf
|
charset utf-8;
|
/etc/nginx/nginx.conf
|
error_log stderr error;
server {
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 |
/etc/nginx/nginx.conf
|
access_log /var/log/nginx/access.log combined;
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
server {
access_log /var/log/nginx/mon_site_access.log;
access_log off;
log_not_found off;
access_log /path/to/log.gz combined gzip=9 flush=5m;
|
 |
« 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
|
http {
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
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
|
$cookie_COOKIE |
contenu du cookie COOKIE
|
$http_HEADER |
contenu du header HEADER (ex: http_user_agent)
|
/etc/nginx/nginx.conf
|
map $remote_addr $loggable {
~^192\.168\.0\. 0; 0;
default 1;
}
access_log /path/to/access.log combined if=$loggable;
map $remote_addr$request $loggable {
~^192\.168\.0\. 0;
"~*GET /wiki/" 1;
default 0;
}
|
Buffer limitations
/etc/nginx/nginx.conf
|
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 8 32k;
proxy_buffers 8 32k;
proxy_buffer_size 64k;
|
Timeout
/etc/nginx/nginx.conf
|
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 {
location = / { }
location / { }
location /mon_dossier/ { }
location ^~ /mon_dossier2/ { }
location ~* \.(gif|jpg|jpeg)$ { }
location ~ /(dossier1|dossier2)/ { }
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. |
Configuration du bloc location
/etc/nginx/nginx.conf
|
allow 192.168.0.0/24;
deny all;
location ~ Spécial {
allow 192.168.0.1;
deny all;
}
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 |
Restreint l'accès aux requêtes internes.
 |
Dans le cas d'une requête externe, l'erreur 404 est renvoyée. |
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;
try_files $uri $uri/fichier1.html $uri/fichier2.html @other;
location @other { }
try_files $uri $uri/fichier1.html $uri/fichier2.html =404;
|
/etc/nginx/nginx.conf
|
location = /index.php {
rewrite .* /index.php/$arg_title? permanent;
}
location / {
try_files $uri $uri/ @rewrite;
}
location @rewrite {
rewrite ^/(.*)$ /index.php?title=$1&$args;
}
|
 |
Les arguments sont ajoutés à la fin de la nouvelle. Pour éviter cela, ajouter un '?' à la fin de la nouvelle url. |
/etc/nginx/nginx.conf
|
root /srv/http/mon_site;
location ^~ /autre_dossier {
alias /un/autre/dossier;
}
location ^~ /dossier {
alias /data/dossier;
}
location ^~ /dossier {
root /data;
}
|
Permet de définir les pages à afficher en cas d'erreurs.
/etc/nginx/nginx.conf
|
error_page 404 /404.html;
error_page 404 =200 /404.html;
error_page 403 /error403.html;
location = /error403.html {
internal;
allow all;
}
|
/etc/nginx/nginx.conf
|
autoindex on;
|
/etc/nginx/nginx.conf
|
location ~* \.(js|css|swf|png|jpg|jpeg|gif|ico|bmp|svg)$ {
expires max;
access_log off;
}
|
- max → sets the Expires header to 31 December 2037 23:59:59 GMT
- 10d → en cache pendant 10 jours (m: minutes, h: hours, d: days, w: weeks, M: months, y: years)
Les hôtes virtuels de NGINX sont appelés blocs serveur.
/etc/nginx/nginx.conf
|
http {
server {
server_name site1;
}
server {
server_name site2 alias2 *.domain.com ~^www\d+\.example\.com$;
}
server {
listen 80 default_server;
index index.html;
root /usr/share/nginx/html;
}
|
/etc/nginx/nginx.conf
|
server {
server_name www.old-name.com old-name.com;
return 301 $scheme://www.new-name.com$request_uri;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ .(aspx|php|jsp|cgi)$ {
deny all;
}
rewrite ^/listings/(.*)$ /listing.html?listing=$1 last;
|
/etc/nginx/nginx.conf
|
location / {
if ($my_var) {
return 200;
}
if (!-e $my_var) {
return 200;
}
|
variable
|
valeur
|
commentaire
|
$1 .. $9 |
|
correspond aux groupes 1 à 9 dans le cadre d'une expression rationnelle
|
$document_root |
/srv/http/monsite |
définit par la directive root /usr/share/webapps/mysite;
|
$fastcgi_script_name |
/page.php |
nom du fichier de script
|
$fastcgi_path_info |
/article/123 |
pour la requête /page.php/article/123
|
$uri |
/page.php/article/123 |
pour la requête /page.php/article/123
|
$arg_name |
text |
pour la requête /page.php?name=text
|
/etc/nginx/nginx.conf
|
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
|
/etc/nginx/.htpasswd
|
user_name:mot_de_passe_hashé
|
|
printf "USER:$(openssl passwd -apr1)\n" >> /etc/nginx/.htpasswd
|
htpasswd
|
htpasswd -c /etc/nginx/.htpasswd user_name
htpasswd /etc/nginx/.htpasswd user_name
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. |
/etc/nginx/nginx.conf
|
limit_conn_zone $binary_remote_addr zone=addr:10m;
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
|
limit_req_zone $binary_remote_addr zone=flood:10m rate=1r/s;
limit_req zone=flood burst=5;
limit_req_status 444;
|
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
Sécurité
/etc/nginx/nginx.conf
|
add_header Strict-Transport-Security "max-age=31536000";
add_header Content-Security-Policy "upgrade-insecure-requests";
server_tokens off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Xss-Protection "1; mode=block" always;
ssl_ciphers "HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers On;
ssl_dhparam /path/dhparams.pem;
ssl_stapling on;
ssl_session_cache shared:SSL:10m;
|
/etc/uwsgi/mysite.ini
|
php-set = expose_php=Off
|
Création d'un certificat
|
cd /etc/ssl/private
openssl genrsa -out server.key 4096
chmod 400 server.key
openssl req -new -sha512 -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
|
Configuration
/etc/nginx/nginx.conf
|
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;
}
|
/etc/nginx/php_files.conf
|
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include /etc/nginx/fastcgi.conf;
}
|
status
Permet de connaître
- le nombre de connexions actuellement ouvertes
- le nombre de connexions acceptés
- le nombre de requêtes gérées
- le nombre de requêtes par seconde = handles requests / handled connections
/etc/nginx/nginx.conf
|
location /status {
stub_status on;
access_log off;
allow x.x.x.x;
deny all;
}
|
/etc/nginx/nginx.conf
|
if ($http_user_agent ~ (Wget|curl) ) {
return 403;
}
|
 |
- « ~ » sensible à la casse
- « ~* » non sensible à la casse
|
/etc/nginx/nginx.conf
|
if ($request_method = POST ) {
return 405;
}
set $test "";
if ($request_method = POST) {
set $test P;
}
if ($http_cookie_cccc) {
set $test "${test}C";
}
if ($test = PC) {
}
location / {
error_page 418 = @other;
recursive_error_pages on;
if ($something) {
return 418;
}
}
location @other { }
|
If Is Evil
uwsgi et nginx
modifier1
|
packet type
|
9 |
Standard Running CGI scripts on uWSGI request followed by the HTTP request body
|
14 |
Standard Running PHP scripts in uWSGI request followed by the HTTP request body
|
30 |
Standard WSGI request followed by the HTTP request body. The PATH_INFO is automatically modified, removing the SCRIPT_NAME from it
|
|
location ~ \.php5?$ {
uwsgi_read_timeout 90;
|
PHP
php-fpm
|
sudo pacman -S php-fpm
sudo systemctl start php-fpm
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$ {
try_files $uri =404;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
include /etc/nginx/fastcgi.conf;
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
|
|
touch /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.
Modifiez la configuration PHP
/etc/nginx/nginx.conf
|
set $session_root /var/www/dev/$1/sessions;
fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:/other/folder\nsession.save_path=$session_root";
|
 |
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. |
/etc/nginx/sites-available/webapp.conf
|
server {
listen 80;
server_name webapp.local;
location ^~ /api/ {
rewrite ^/api(/.*)$ $1 break;
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://localhost:5001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
|
Modules
/etc/nginx/nginx.conf
|
load_module /usr/lib/nginx/modules/ngx_http_echo_module.so;
http {
server {
location / {
default_type text/plain;
echo "hello, world!";
echo_sleep 1;
|
/etc/nginx/nginx.conf
|
load_module /usr/lib/nginx/modules/ngx_http_js_module.so;
http {
js_include /etc/nginx/scripts/my_script.js;
server {
location / {
default_type text/plain;
js_content my_function;
|
/etc/nginx/scripts/my_script.js
|
function my_function(r) {
r.return(200, "Hello world!");
r.return(302, 'http://domain.net');
}
function read_file() {
var fs = require('fs');
try {
var file_content = fs.readFileSync('/tmp/my_file.txt', 'utf8');
if (file_content === '0\n') {
}
} catch (e) {
}
}
|
Erreurs
could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 6
/etc/nginx/nginx.conf
|
types_hash_max_size 4096
|
could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32
Nom de serveur trop long par rapport aux règlages → augmenter la taille autorisée des noms de serveur.
/etc/nginx/nginx.conf
|
http {
server_names_hash_bucket_size 64;
|
client intended to send too large body
Augmenter la valeur de client_max_body_size
/etc/nginx/nginx.conf
|
http, server, location {
client_max_body_size 20m;
|
Mediawiki
/etc/nginx/nginx.conf
|
location = / {
return 301 /wiki/Accueil;
}
location ^~ /cache/ {
deny all;
}
location ^~ /images/ { }
location ^~ /sitemap/ { }
location = /sitemap.xml { }
location ^~ /wiki/ {
rewrite ^/wiki/(?<pagename>.*)$ /index.php;
}
location / {
return 404;
}
location ~ /\w+\.php {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
try_files $uri =404;
expires max;
log_not_found off;
}
|
LocalSettings.php
|
$wgArticlePath = "/wiki/$1";
|
Pretty URL avec uwsgi
/etc/nginx/nginx.conf
|
error_page 403 404 = /index.php;
location ~ \.php5?$ {
include uwsgi_params;
uwsgi_modifier1 14;
uwsgi_pass unix:/run/uwsgi/mediawiki.sock;
}
location ^~ /wiki/ {
rewrite ^/wiki/(.*)$ /index.php?title=$1;
}
location ^~ /cache/ { deny all; }
location ^~ /images/deleted/ { deny all; }
location ^~ /images/temp/ { deny all; }
location ^~ /includes/ { deny all; }
location ^~ /languages/ { deny all; }
location ^~ /maintenance/ { deny all; }
location ^~ /maintenance/archives/ { deny all; }
location ^~ /serialized/ { deny all; }
location ^~ /tests/ { deny all; }
location ^~ /extensions/MobileFrontend/dev-scripts/ { deny all; }
location ^~ /mw-config/ { deny all; }
location ^~ /extensions/ { deny all; }
location ^~ /resources/ { deny all; }
location ^~ /resources/assets/ { allow all; }
location ^~ /docs/ { internal; }
location ^~ /vendor/ { internal; }
location ~ /.ht { deny all; }
location ~* \.(js|css|png|jpg|jpeg|svg|gif|ico)$ {
try_files $uri /index.php;
expires max;
}
|
LocalSettings.php
|
$wgArticlePath = "/wiki/$1";
|
/etc/nginx/nginx.conf
|
server {
listen 80;
server_name myserver;
root /srv/http/myserverfolder;
index index.php;
location ~ /cache|images/deleted|languages|maintenance|maintenance/archives|serialized|tests/ {
deny all;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include /etc/nginx/fastcgi.conf;
}
|
 |
Le fichier robots.txt devra correspondre aux urls de type /index.php?title=MonTitre |
/etc/nginx/nginx.conf
|
server {
location / {
try_files $uri $uri/ /index.php?$args;
}
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|
jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}
location ~ [^/]\.php(/|$) {
include uwsgi_params;
uwsgi_modifier1 14;
uwsgi_pass unix:/run/uwsgi/wordpress.sock;
}
}
|
 |
Wordpress a besoin d'autoriser l'ip du serveur pour ses taches cron. |
|
sudo pacman -S nginx
sudo systemctl start nginx
|
 |
The default served page at http://127.0.0.1 is /usr/share/nginx/html/index.html |