Nginx & Gatsby 🔧 Configuration d'un site web en production
Bien qu'il soit beaucoup plus aisé de mettre en route un site pré-compilé en production qu'un site dynamique, il y a tout de même une série de réglages à effectuer sur le serveur HTTP de mon choix, Nginx.
Cette compilation de directives glanées à droite à gauche peut s'appliquer sur d'autres rendus de sites HTML que Gatsby, à l'instar d'Eleventy ou autre. Vous constaterez que ce sont des principes généraux, pour la plupart.
Notez qu'elle évoluera car la partie sécurité concerne surtout les vieux navigateurs, le Content Security Policy (ou CSP) étant amené à supplanter ou compléter la plupart des anciennes directives.
Configuration de départ
On commence par une configuration nginx standard d'un dossier contenant les fichiers statiques générés par Gatsby. Le tout chiffré et servi via HTTP/2.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name juliancataldo.com www.juliancataldo.com;
location / {
root /srv/repos/juliancataldo.com/production;
}
}
Notez que ma configuration SSL (utilisant des clefs Let's encrypt) est gérée séparemment, dans un snippet global pour mes différents sites.
Router la page 404 de Gatsby
Par défault, nginx ne résoudra pas le chemin des pages introuvables généré par Gatsby.
Pour remédiez à cela, ajoutez cette directive au bloc server
:
# Indique l'emplacement pour les pages introuvables.
error_page 404 /404.html;
Économiser de la bande-passante grace à gzip
Les ressources textuelles (html, css, svg, json..) profitent particulièrement de la compression gzip à la volée supportée par nginx. Veillez à bien
spécifier les types MIME concernés.
Attention, les images (jpeg, png…) ou les polices de caractères (woff), déjà compressées ne profitent pas de cette optimisation, c'est même l'inverse.
gzip on;
# Une valeur élevée sollicite plus fortement le processeur.
gzip_comp_level 5;
gzip_types text/plain text/css application/javascript application/x-javascript text/xml application/xml application/rss+xml text/javascript image/x-icon image/bmp image/svg+xml application/json;
Il n'est pas rare d'observer des gains de 50% à 75% du poids initial.
Définir l'encodage du texte dans les entêtes HTTP
Bien que l'encodage UTF-8 puisse être spécifié dans la balise racine d'un document html en modifiant le template de base de Gatsby, /src/html.js
de cette façon :
{/* ./src/html.js */}
…
<html lang="fr" charSet="utf-8">
…
Il est toutefois préconisé de le faire aussi en amont, au sein même des entêtes HTTP.
Pour cela, ajouter ces directives dans le bloc server
:
# Définit l'encodage en amont du chargement du document.
charset utf-8;
charset_types text/html text/plain application/json;
Désormais, le navigateur sait interpréter le jeu de caractères avant même de recevoir le moindre octet du document HTML demandé. En revanche je ne saurais vous dire si les gains sont mesurables…
Établir une politique de mise en cache basique
Facteur considéré comme « vital » par les métriques de Google, la mise en cache des fichiers statiques évite à vos
visiteurs de les re-télecharger à chaque visite.
Par défaut, les navigateurs ne conservent ces fichiers que durant la session de
navigation.
À noter : Il faut définir le même chemin racine que dans le bloc location /
.
Ajouter le bloc suivant dans le bloc parent, server
:
location ~* \.(js|json|css|png|jpg|jpeg|gif|ico|woff2)$ {
# En jours.
expires 365d;
# Autoriser la mise en cache aux intermédiaires (proxys, navigateur…),
# interdire son altération.
add_header Cache-Control "public, no-transform";
# Reprendre la racine dans le bloc 'location' principal.
root /srv/repos/juliancataldo.com/production;
}
Sécuriser les requêtes HTTP, les rudiments
1. Chiffrement
Tout d'abord, pour se prémunir de certaines attaques de l'« homme au milieu » 🦹♂️ (ou man-in-the-middle), forçons l'utilisation du SSL par les clients.
# Forcer le HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
2. Iframes
Ensuite on décide de n'accepter les urls dans les iframes que si elles proviennent de la même origine que votre site (donc pas de problème pour un chargement d'un vidéo YouTube par ex.), ceci afin d'éviter le détournement de clicks (click-jacking).
# Bloquer les urls dans les iframes qui n'ont pas la même
# origine que la page. Prévient le détournement de clicks.
add_header X-Frame-Options SAMEORIGIN always;
3. Scripts
Bloquer le chargement de la page si une attaque de script croisés (cross-site-scripting) est detectée.
# Bloque le chargement en cas de détection d'attaque XSS.
add_header X-XSS-Protection "1; mode=block";
4. Types MIME
Forcer une définition stricte des types MIME pour éviter le reniflage (sniffing).
# Empêcher le reniflage des types MIME.
add_header X-Content-Type-Options nosniff;
L'ensemble de ces 4 directives est à ajouter au bloc parent, server
.
Utiliser les politiques de sécurité du contenu (à venir)
Comme dit au début de l'article, une mise-à-jour sera apportée pour parler des entêtes plus modernes, les Content Security Policy (ou CSP).
Configuration finale
Voici le fichier de configuration nginx final reprenant toutes les directives pré-citées :
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name juliancataldo.com www.juliancataldo.com;
gzip on;
# Une valeur élevée sollicite plus fortement le processeur.
gzip_comp_level 5;
gzip_types text/plain text/css application/javascript application/x-javascript text/xml application/xml application/rss+xml text/javascript image/x-icon image/bmp image/svg+xml application/json;
# Définit l'encodage en amont du chargement du document.
charset utf-8;
charset_types text/html text/plain application/json;
# Forcer le HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Bloquer les urls dans les iframes qui n'ont pas la même
# origine que la page. Prévient le détournement de clicks.
add_header X-Frame-Options SAMEORIGIN always;
# Bloque le chargement en cas de détection d'attaque XSS.
add_header X-XSS-Protection "1; mode=block";
# Empêcher le reniflage des types MIME.
add_header X-Content-Type-Options nosniff;
location / {
root /srv/repos/juliancataldo.com/production;
}
location ~* \.(js|json|css|png|jpg|jpeg|gif|ico|woff2)$ {
# En jours.
expires 365d;
# Autoriser la mise en cache aux intermédiaires,
# interdire son altération.
add_header Cache-Control "public, no-transform";
# Reprendre la racine dans le bloc 'location' principal.
root /srv/repos/juliancataldo.com/production;
}
# Indique l'emplacement pour les pages introuvables.
error_page 404 /404.html;
}
Vous pouvez maintenant profiter sur votre site des gains de performances et de sécurité qu'apportent ces quelques optimisations pour Nginx 😄.