Nginx: cacher la version dans les headers http

nginx-logo

Par défaut, Nginx affiche sa version dans les headers http. On peut pour des raisons de veilles versions ou de vulnérabilités vouloir cacher cette version.

Par défaut nous avons ceci :

$ curl -I https://www.cloud-devops.fr/
HTTP/1.1 200 OK
Server: nginx/1.9.10
Date: Fri, 05 Feb 2016 20:57:50 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding

Si l’on veut ne plus afficher la version 1.9.10, il faut ajouter dans le bloc « http » l’option :

server_tokens off;

Après un restart de Nginx, nous obtenons ceci :

$ curl -I https://www.cloud-devops.fr/
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 05 Feb 2016 21:04:09 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding

Voilà ça fonctionne ! Notre version de Nginx est maintenant masquée aux utlisateurs.

Nginx : Activer la compression GZIP

gzip_compress

C’est toujours dans une approche d’optimization de notre serveur ainsi que de l’expérience utilisateur que nous allons aborder la mise en place de la compression Gzip des requêtes http sur Nginx. Nous avons déjà vu comment mettre en cache nos fichiers statiques pour rendre notre site plus rapide.  Ici nous allons voir comment compresser nos requêtes.

Vous devez avoir le module ngx_http_gzip_module de compiler sur votre nginx. C’est généralement le cas par défaut.

Les paramètres gzip sont à mettre dans le bloc « http » généralement ce bloc se trouve dans le fichier nginx.conf.

On y ajoute les paramètres suivants :

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 4 32k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/x-font-ttf application/javascript font/eot font/opentype image/svg+xml image/x-icon text/plain;

Et l’on redémarre nginx.
Les lignes les plus importantes sont gzip on; et gzip_types.

Quelques explications :

  • gzip on : active la compression
  • gzip_types : permet de spécifier quel type de fichiers doit être compressé.
  • gzip_vary : permet d’ajouter dans le header « Vary: Accept-Encoding” ce qui permet au proxy de stocker une version compressée et non compressée du fichier.
  • gzip_proxied : permet de compresser les requêtes venant de proxies.
  • gzip_comp_level : determine le niveau de compression. Plus la compression sera élevée plus la requête sera petite mais le client perdra un peu plus de temps à la décompresser.
  • gzip_buffers 4 32k : le premier chiffre (4) correspond au nombre et le deuxième à la taille du buffer utilisés pour compresser la requête.
  • gzip_http_version : permet de spécifier la version http qui doit être compressée.

On peut surcharger nos paramètres en le mettant dans le bloc « server ».
Par exemple si l’on met gzip off dans un bloc « server » cela désactivera la compression gzip sur notre domaine.

Test

Nous allons tester à l’aide de curl si nos paramètres sont bien pris en compte.

$ curl -I --header "Accept-Encoding: gzip" https://www.cloud-devops.fr/
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 05 Feb 2016 14:32:20 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Content-Encoding: gzip

Si vous voyez « Vary: Accept-Encoding » et « Content-Encoding: gzip » c’est que votre serveur est bien paramétré.

Pour plus d’infos sur le module gzip voici le documentation nginx officiel gzip 

Nginx: mise en cache des fichiers statiques

nginx

Il est très important de bien configurer votre serveur nginx pour servir correctement les fichiers statiques (images, javascript, css, texte …).
Cela vous permet d’économiser la bande passante de votre serveur et également d’améliorer l’expérience utilisateur. L’utilisateur aura l’impression que votre site se charge plus vite.
L’utilisateur n’aura pas besoin de télécharger de nouveau ce fichier js ou l’image car son navigateur l’aura déjà dans son propre cache.

La mise en cache des fichiers statiques, coté du navigateur, se fait à l’aide des headers renvoyés par le serveur.
Il faut être sur d’avoir le module ngx_http_headers_module compilé avec nginx. C’est le cas par défaut.
Il y a plusieurs paramètres à mettre en place pour configurer correctement nos headers.

Prenons l’exemple suivant :

location ~* \.(png|jpg|jpeg|gif|ico|woff|otf|ttf)$ {
  root /var/www/static/;
  access_log off;
  log_not_found off;
}

1. expires

Ce paramètre permet de contrôler la durée de mise en cache. Il est par défaut à off. La directive expires permet d’agir sur les headers http Expires et Cache-Control
Ce paramètre peut prendre différents paramètres epoch,max,une durée, off ou une heure.

  • off: désactive les headers http Expires et Cache-Control
  • epoch: met le header Expires à la date du 1 January, 1970 00:00:01 GMT.
  • max: met le header Expires à la date du Thu, 31 Dec 2037 23:55:55 GMT et le Cache-Control au maximum c’est à dire à 10ans
  • une durée: met le cache à une durée relatif par rapport à l’accès au fichier. Par exemple expires 10d; signifie que votre navigateur conservera cette version de fichier pendant 10 jours.
  • une heure: met une heure à partir de laquelle de fichier expire dans la journée. Il doit être préfixé par un @. Par exemple expires @12:10; signifie que votre fichier va expiré à 12h10

Dans la plupart des cas un expires max; ou expires 1y; sera bien efficace. Dans notre exemple cela donne :

location ~* \.(png|jpg|jpeg|gif|ico|woff|otf|ttf)$ {
  root /var/www/static/;
  access_log off;
  log_not_found off;
  expires 1y;
}

2. add_header

Cette directive prend des options libres c’est à nous de renseigner ce que l’on veut. Nos paramètres doivent correspondre aux standard du protocol http pour être interprété par l’ensemble des navigateurs et proxies.

Nous allons intervenir sur le header Cache-Control. Avec le paramètre expires nous sommes déjà intervenu sur le cache-control pour mettre max-age=31536000. Il faut maintenant décrire la façon dont cela doit être conserver. Plusieurs options sont à notre disposition :

  • no-cache : cela indique que la prochaine requête sur la même url devra être validé par le serveur pour confirmer qu’elle n’a pas changé.
  • no-store : interdit de stocker la réponse. On ne l’utilise pas pour les fichiers statiques mais généralement sur des urls qui contiennent des données confidentielles (mon compte par exemple).
  • private: ne sera mis en cache que par les navigateurs et jamais par les serveurs proxies.
  • public: peut être stocké par n’importe qui. Ce paramètre est implicite si le paramètre max-age est déjà en place.

Nous allons donc de notre coté mettre le paramètre add_header Cache-Control « public »; qui va permettre de mettre nos fichiers en cache pour tout le monde et de les stocker. Dans notre exemple cela donne :

location ~* \.(png|jpg|jpeg|gif|ico|woff|otf|ttf)$ {
  root /var/www/static/;
  access_log off;
  log_not_found off;
  expires 1y;
  add_header Cache-Control "public"; 
}

3. Test

A l’aide d’un curl nous allons tester que cela fonctionne.

$ curl -I https://www.cloud-devops.fr/wp-content/uploads/2016/02/log_nginx.jpg
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 05 Feb 2016 12:07:27 GMT
Content-Type: image/jpeg
Content-Length: 181406
Last-Modified: Thu, 04 Feb 2016 21:31:59 GMT
Connection: keep-alive
ETag: "56b3c34f-2c49e"
Expires: Sat, 04 Feb 2017 12:07:27 GMT
Cache-Control: max-age=31536000
Pragma: public
Cache-Control: public
Vary: Accept-Encoding
Accept-Ranges: bytes

Nous avons le header Cache-Control à public, le Cache-control max-age à 365 jours et un Expires à la date du Sat, 04 Feb 2017 12:07:27 GMT. Tout fonctionne parfaitement !

Nginx: exclure un user agent de nos logs

log nginx

Nous avons vu précédemment que nous pouvions exclure des logs nginx une url spécifique et même une adresse ip.

Nous allons voir ici, comment exclure de nos logs un user agent spécifique. Par exemple nous ne voulons pas avoir dans nos logs le user agent de notre monitoring « mymonitoringBot » ou encore celui de « Googlebot ».

Nous allons créer un bloc « map » pour y mettre nos règles :

map $http_user_agent $log_useragent {
  ~Googlebot 0;
  ~mymonitoringBot 0;
  default 1;
}

On assigne la valeur 0 aux user agent Googlebot et mymonitoringBot. Toutes les autres user agent auront la valeur 1.
Il suffit ensuite de mettre cette condition dans notre bloc « server« .

server {
   ...
access_log /var/log/nginx/access.log main if=$log_ua;

}

N’entrerons dans les logs que la valeur 1 qui correspond à la valeur par défaut. Notre fichier access.log ne contiendra pas les user agent Googlebot et mymonitoringBot.

Nginx : exclure une ip des logs

log nginx

Pour des raisons pratiques, on peut vouloir exclure de nos logs nginx une ou plusieurs adresses ip.

Nginx déconseille d’utiliser le « if » dans la configuration de nginx et le considère comme le mal !

1. Nise en place d’un bloc map

Nous allons créer un bloc « map » pour y mettre la liste des adresses ips.  Ce bloc « map »  doit être créer en dehors du bloc « server« .

Vous pouvez avoir envie d’exclure le localhost ou encore l’ip de votre monitoring.

map $remote_addr $log_ip {
     "127.0.0.1" 0;
     "1.2.3.4" 0;
    default 1;
}

On assigne la valeur 0 aux adresses ip 127.0.0.1 et 1.2.3.4. Toutes les autres adresses ip auront la valeur 1.

2. Mise en place du filtre

Il suffit ensuite de mettre dans le bloc « server » notre condition sur nos logs.

server {
     ...

     access_log /var/log/nginx/access.log main if=$log_ip;
}

Les adresses ip 127.0.0.1 et 1.2.3.4 n’apparaitront plus dans le log access.log.

Nginx: exclure une url des logs

nginx exclure url

On peut vouloir exclure des urls spécifiques dans nos logs. Cela facilitera les futurs recherches par exemple.

Dans la config de nginx, on utilise très souvent le bloc « location »  pour définir les paramètres d’un type d’url, par exemple pour servir les fichiers statiques.

Vous avez sans doute ce type de configuration :

location ~* \.(png|jpg|jpeg|gif|ico|js|css)$ {
   root /var/www/static/;
   expires max; 
}

Pour que les urls de nos images, js ou css n’apparaissent pas dans nos logs, il suffit d’ajouter l’option « access_log off; »
Comme ceci :

location ~* \.(png|jpg|jpeg|gif|ico|js|css)$ {
   root /var/www/static/;
   expires max; 
   access_log off;
   log_not_found off;
}

Vous pouvez noter que j’ai également ajouter l’option « log_not_found off; » qui permet de ne pas écrire dans le fichier « error_log » les fichiers manquants.

Comment débannir un ip de Fail2ban

fail2ban debannir ip

Il existe un utilitaire en ligne de commande qui permet d’agir sur fail2ban.

Il s’agit de fail2ban-client. Il s’utilise de cette façon :

fail2ban-client set JAILNAME unbanip IPADDRESS

Pour connaitre le vrai « JAILNAME », on peut utiliser cette commande :

# iptables -L -n 
target prot opt source destination
fail2ban-ssh tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 22

Chez moi, « JAILNAME » correspond à fail2ban-ssh

Ce qui donne la commande suivante :

# fail2ban-client set ssh unbanip 1.2.3.4

Configurer http2 sur nginx

nginx http2

Depuis sa version 1.9.5, nginx apporte le support du protocole http version 2. Si vous utilisiez déjà le module SPDY, il est remplacé par le module HTTP/2.

Pour savoir si vous supportez ce protocole :

# nginx -V

Vous devez avoir une version supérieur à 1.9.5 et avoir dans les options de compilations –with-http_v2_module. Si vous n’avez pas cette option, il faudra mettre à jour votre version de nginx.

Il faut savoir que l’implémentation de HTTP/2 requière du HTTPS.

1. Configuration :

Pour ajouter la prise en charge de HTTP/2 dans la configuration de nginx, il suffit de remplacer dans le bloc server { }

listen 443 ssl;

par :

listen 443 ssl http2;

On recharge ensuite la config :

# service nginx restart

2. Test :

Pour vérifier que cela fonctionne correctement je vous invite à faire le test sur :

https://tools.keycdn.com/http2-test