À la recherche de la configuration parfaite pour NGINX

1/52/53/54/55/5 (5 votes, moyenne: 4,20 sur 5)
Loading...
À

Attention, cet article a plus d'une année d'ancienneté. Il est possible que les informations présentées ne soient plus à jour, spécialement dans le cadre d'un article technique.


Bonjour à tous,

À la suite de l’article Compiler NGINX, pourquoi ? Comment ?, j’avais envie de vous faire un petit article sur ma recherche personnelle (pour l’instant aucun commit sur github) de la configuration parfaite pour NGINX qui permets de trouver le meilleur équilibre entre les performances et la sécurité (sans négliger l’un ou l’autre).

 

Je reprécise pour ceux qui lissent en diagonale, ce n’est (peut-être) pas la configuration parfaite, mais j’aimerais un coup de main pour que ça le devienne 🙂

 

Les besoins :

Avant tout, il faut comprendre mes besoins :

Le fichier de configuration nginx.conf doit fonctionner pour la dernière mainline de NGINX et OpenSSL 1.1.0 (ou la dernière version stable de OpenSSL).

Il est nécessaire d’avoir au minimum les résultats suivants sur différents tests en ligne :

 

Aussi, la configuration ne doit pas être destructrice ou trop restrictive.

Cela explique deux choses :

  • Premièrement, TLS 1.0 et 1.1 sont actifs.
  • Deuxièmement, Content-Security-Policy n’est pas dans son réglage le plus strict.

 

 

Détail de la configuration actuelle :

La dernière configuration en date est toujours disponible sur mon repo GitHub.

Pour information, je me base sur mon serveur Web qui dispose d’un Intel Xeon D-1531 avec 32Gb de RAM pour faire cette configuration, ce qui explique certaines valeurs assez élevées.

Faites jouer les divisions (ou les multiplications) pour adapter le bordel à votre serveur.

 

Le début du fichier :

On commence par déclarer l’utilisateur et le pid avec lesquels NGINX va se lancer.

En plus de cela on indique le nombre de processus de Nginx que l’on souhaite lancer en parallèle.

Idéalement, il en faut un ou deux par cœurs / thread.

user www-data;
worker_processes 12; # Number of CPU Cores
pid /run/nginx.pid;

 

La partie Events :

La première chose que l’on déclare ici, c’est les worker_connections.

C’est le nombre maximum de personnes que votre serveur NGINX peut servir en simultané. Pas de calcul miracle ici, ajustez le en fonction de vos tests de charges.

Multi_accept est activé ici pour pouvoir démarrer plusieurs nouvelles connexions en parallèle. Si vous n’activez pas ce paramètre, vous aurez vite un blocage.

Finalement, epoll est utilisé en tant que mécanisme d’entrée / sortie pour des performances améliorées lors des fortes charges.

events {
 worker_connections 16384;
 multi_accept on;
 use epoll;
}

 

Enfin, on défini la variable worker_rlimit_nofile, voyez ce post pour plus d’informations.

Pour faire simple :

# worker_rlimit_nofile = (worker_connections * 1) + 500
# worker_rlimit_nofile = (worker_connections * 2) + 500 si on utilise NGINX en tant que reverse proxy.

worker_rlimit_nofile 16884;

 

Les paramètres TLS :

On passe les paramètres basiques et on attaque directement la partie TLS.

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_ecdh_curve X25519:sect571r1:secp521r1:secp384r1;
 ssl_session_timeout 1d;
 ssl_session_cache shared:SSL:50m;
 ssl_session_tickets off;
 ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305-D:ECDHE-RSA-CHACHA20-POLY1305-D:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384';
 ssl_prefer_server_ciphers on;

 

Comme indiqué précédemment, j’autorise tous les protocoles TLS pour une plus large compatibilité.

On utilise uniquement des courbes ECDH pour les échanges, a savoir : X25519, sect571r1, secp521r1 et secp384r1.

Cela nous permet d’être compatible avec beaucoup de monde tout en gardant le meilleur niveau de sécurité possible.

Le timeout des sessions est réglé sur une journée. Le cache entre toutes les sessions est lui réglé sur 50 minutes.

On désactive les tickets de sessions ssl car ce n’est pas sécurisé. Voir ce post pour plus d’informations.

 

Enfin, on liste spécifiquement tous les chippers que l’on autorise et on force le client a utilisé les préférences du serveur.

 

Les paramètres d’header :

Ah les headers, l’une des choses les plus importantes pour la sécurité d’un serveur web qui est bien trop souvent complètement oublié au bénéfice des paramètres de caches ou des paramètres d’échange TLS.

Dans un premier temps, on va désactiver toutes les informations renvoyées par NGINX pour que votre numéro de version ne soit pas renvoyé en clair.

server_tokens off;

 

Ensuite, on va régler tous les headers nécessaires pour la sécurité de vos visiteurs de vos sites.

Dans un premier temps, on active HSTS avec les paramètres recommandés :

 add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";

 

Ensuite, on autorise uniquement les Iframes provenant du même domaine :

 add_header X-Frame-Options "SAMEORIGIN" always;

 

Ensuite, on configure CSP pour autoriser uniquement les contenus externes en HTTS :

 add_header Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'" always;

 

On active la protection contre les attaques Xss et MIME :

add_header X-Xss-Protection "1; mode=block" always;
 add_header X-Content-Type-Options "nosniff" always;

 

Pour finir, vous devez aussi activer la validation OCSP pour vos certificats en suivant ce tutoriel.

 ssl_stapling on;
 ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/private/ocsp-certs.pem
 resolver 8.8.4.4 8.8.8.8 valid=300s;
 resolver_timeout 5s;

 

Les paramètres des logs :

Ici on désactive simplement les access logs pour la performance. On garde uniquement les erreurs :

access_log off;
 error_log /var/log/nginx/error.log;

 

Les paramètres GZIP :

Rien de bien nouveau ni de transcendant ici, on règle simplement le niveau de compression sur 6 en indiquant les types de fichiers que l’on compresse.

gzip on;
 gzip_disable "msie6";
 gzip_vary on;
 gzip_proxied any;
 gzip_comp_level 6;
 gzip_buffers 16 8k;
 gzip_http_version 1.1;
 gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

 

Les paramètres de caches et de performances :

On active d’abord sommairement les Threads AIO pour de gros gains de performances. Pour plus d’informations, lisez le post de Nginx.

 aio threads;

 

Ensuite, on active une mitigation très basique contre les attaques par déni de service. Pour plus d’informations, regardez mon article de l’époque.

 ##Max c/s by ip
 limit_conn_zone $binary_remote_addr zone=limit_per_ip:10m;
 limit_conn limit_per_ip 40;

##Max rq/s by ip
 limit_req_zone $binary_remote_addr zone=allips:10m rate=400r/s;
 limit_req zone=allips burst=400 nodelay;

 

On définit tous les paramètres de cache pour tout ce que l’on n’a pas vu avant.

Pas de recette miracle, il faut potasser le wiki de nginx et faire du bench. Voici ce que j’utilise moi.

#PHP
 fastcgi_buffers 256 32k;
 fastcgi_buffer_size 256k;
 fastcgi_connect_timeout 4s;
 fastcgi_send_timeout 120s;
 fastcgi_read_timeout 120s;
 fastcgi_busy_buffers_size 512k;
 fastcgi_temp_file_write_size 512K;
 reset_timedout_connection on;

#Others
 open_file_cache max=2000 inactive=20s;
 open_file_cache_valid 60s;
 open_file_cache_min_uses 5;
 open_file_cache_errors off;

client_max_body_size 50M;
 client_body_buffer_size 1m;
 client_body_timeout 15;
 client_header_timeout 15;
 keepalive_timeout 65;
 send_timeout 15;
 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;

 

Vous l’aurez compris, pas de miracle, mais beaucoup de doc potassée pendant plusieurs années d’utilisation de NGINX.

Si des gens veulent contribuer et apporter leurs lignes de configurations à l’édifice, il faut aller sur le github : https://github.com/stylersnico/nginx-secure-config/

 

Le fichier de configuration a jour est toujours disponible ici : https://github.com/stylersnico/nginx-secure-config/blob/master/nginx.conf

 

Vous aurez besoin d’une version custom de nginx pour utiliser ce fichier de configuration. J’en ai parlé dans le dernier article.

 

Bonne journée 🙂

 

A propos de l'auteur

Nicolas Simond

Ingénieur Systèmes et Réseaux et guitariste hard rock et metal à mes heures perdues.
Je suis le créateur et l'unique rédacteur d'Abyss Project, c'est ici que je note la plupart de mes procédures et quelques divagations.

Si vous l'article vous a aidé, pensez à me payer un café :)

Subscribe
Notify of
guest

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

21 Commentaires
Plus récents
Plus anciens Populaires
Inline Feedbacks
View all comments
Nomad
Nomad
7 années plus tôt

Salut,
peut-être une question bête:
dans ta conf Nginx je vois: #ssl_dhparam /etc/ssl/certs/dhparam.pem; #We no longer use DH, only ECDH
concernant ton tuto: Installer ISPConfig 3.1 avec NGINX, MariaDB et PHP 7 sous Debian 8
c’est finalement plus la peine de générer cette clé ou elle sert aussi à autre chose ?
cd /etc/ssl/certs && openssl dhparam -out dhparam.pem 4096

merci pour ton éclairage 😀

Nomad
Nomad
Reply to  Nicolas Simond
7 années plus tôt

Tant mieux ! parce que c’était long :s
Merci 😉

Qwaser
7 années plus tôt

Merci à toi pour cet article, il m’a permis de comprendre certains paramètres de ma configuration actuelle. En effet j’avais repris ton fichier de configuration depuis un moment, utilisant ton script pour compiler NGINX lorsque j’étais sur Debian avant de passer sur Arch Linux il y a peu. Par contre, j’aurais une question, sur le site de test https://securityheaders.io j’ai toujours le header HTTP Public Key Pinning de manquant. Après recherche j’ai lu qu’il s’agissait de mettre les empreintes en SHA256 de nos certificats. Ce header a-t-il une utilité réel et pourquoi tu ne l’inclus pas dans ta configuration ?… Voir plus »

Qwaser
Reply to  Nicolas Simond
7 années plus tôt

Ah oui à ce point ? Que fait concrètement ce header pour qu’à la moindre erreur ça rend ton site indisponible pour les six prochains mois ?! 😮

Qwaser
Reply to  Nicolas Simond
7 années plus tôt

Donc cela signifie qu’à chaque changement de certificat, la valeur du header est à modifier. Effectivement il ne faut pas l’oublier par contre.

J’ai tenté de le mettre en place dans le fichier de configuration de mon site, seulement ça a eu comme conséquence d’annuler tous les autres header contenu dans nginx.conf xD

Novakin
Reply to  Qwaser
7 années plus tôt

my 2 cents Si tu te plantes avec HPKP tu ne bloques pas l’accès à ton site pendant 6 mois, c’est en fonction du max-age que tu indiques dans le header. Chez moi c’est 1 mois. Le mieux à faire pour mettre en place HPKP c’est commencer par un header en report-only histoire de voir si ces erreurs ressortent. Ensuite tu épingles le HASH de ta clef privée, pas du certificat. Tu t’assures ensuite de ne pas perdre cette clef privée et tu épingles aussi le hash d’une ou deux clefs privée ensuite que tu as en backup. Tu peux… Voir plus »

Nomad
Nomad
7 années plus tôt

Salut,
pour activer Naxsi ne faut-il pas ajouter ceci ?

/etc/nginx/nginx.conf:
# nginx-naxsi config
# Uncomment it if you installed nginx-naxsi
include /etc/nginx/naxsi_core.rules;

/etc/nginx/sites-available/default:
# Uncomment to enable naxsi on this location
include /etc/nginx/naxsi.rules;

Nomad
Nomad
Reply to  Nicolas Simond
7 années plus tôt

Il me semble que c’est le cas avec ton script Build Nginx, Naxsi & OpenSSL dans l’article: Compiler NGINX, pourquoi ? Comment ?
Je parle uniquement de l’activation (reste surement la configuration de Naxsi)

wallace
wallace
7 années plus tôt

Juste une precision sur le access log off, c’est si et seulement si un autre moyen de log est en amont ( reverse proxy, firewall) et qu’il log les connexions. En France avec la LCEN on doit avoir des traces de toutes les connexions pendant 1 an sinon sanction si lors d’une requête judiciaire il n’y a rien.

Marthym
7 années plus tôt

Merci pour les explication, j’ai appris des choses.

Harvester
7 années plus tôt

Petite astuce pour les workers : Nginx gère très bien la gestion automatique du nombre de worker, ainsi que l’affinité CPU de chaque worker pour maximiser les performances. Ca se règle simplement avec ces deux paramètres en début de conf :

worker_processes auto;
worker_cpu_affinity auto;

Nomad
Nomad
Reply to  Harvester
7 années plus tôt

Je mets toujours worker_processes auto;
et ça a l’air de toujours bien fonctionner, justement je voulais poser la question mais depuis j’ai oublié…
Nicolas si tu peux confirmer ça nous permettra d’adapter tes tutos, merci 😉

qwerty
qwerty
7 années plus tôt

Super article, ça va me sauver beaucoup de temps.