Servir des fichiers statiques avec Nginx : conseils d'optimisation

Optimisez la livraison de fichiers statiques avec Nginx grâce à des en-têtes de cache appropriés, la compression Gzip, des valeurs par défaut sûres et des astuces pour protéger les fichiers cachés — pour des sites plus rapides avec moins de problèmes de contenu obsolète.

Servir des fichiers statiques avec Nginx : conseils d'optimisation

Servir des fichiers statiques avec Nginx est l'une des méthodes les plus courantes et efficaces pour délivrer des images, du CSS, du JavaScript, des téléchargements et des actifs frontend construits. Nginx est très compétent pour cette tâche, mais quelques choix de configuration peuvent faire la différence entre un site rapide et prévisible et un site qui gaspille de la bande passante ou sert du contenu obsolète.

L'optimisation des fichiers statiques repose principalement sur des chemins clairs, des en-têtes de cache corrects, la compression et des valeurs par défaut sûres. Vous n'avez pas besoin d'une configuration compliquée pour obtenir de bons résultats, mais les règles de cache doivent correspondre à la façon dont vos fichiers sont nommés et déployés.

Commencez par un emplacement clair pour les fichiers statiques

La configuration la plus simple pour les fichiers statiques utilise root et try_files :

server {
    listen 80;
    server_name example.com;

    root /var/www/example.com/public;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Avec cette configuration, une requête pour /css/app.css correspond à /var/www/example.com/public/css/app.css. Si le fichier n'existe pas, Nginx renvoie 404.

Ce mappage direct est utile lors du débogage. Vous pouvez prendre une URL du navigateur, la transformer en chemin de système de fichiers et vérifier si le fichier existe :

ls -l /var/www/example.com/public/css/app.css

Si le fichier existe mais que Nginx renvoie 404, cherchez une root différente, un bloc location plus spécifique ou un fichier include qui remplace le chemin.

Pour une application monopage, vous pouvez vouloir que les routes inconnues reviennent à index.html :

location / {
    try_files $uri $uri/ /index.html;
}

Cela est utile pour les routeurs frontend, mais ne l'utilisez pas aveuglément pour chaque site. Si des actifs manquants renvoient également index.html, le débogage de chemins JavaScript ou d'images cassés peut devenir déroutant. De nombreuses équipes utilisent un emplacement séparé pour les actifs afin que les fichiers manquants renvoient toujours un vrai 404.

Vous pouvez également utiliser alias lorsqu'un chemin d'URL doit correspondre à un chemin de système de fichiers différent :

location /assets/ {
    alias /srv/shared-assets/;
}

Soyez prudent avec les barres obliques finales. Avec alias, le chemin de l'emplacement et le chemin du système de fichiers doivent généralement tous deux se terminer par /. Une discordance peut produire des chemins de fichiers inattendus.

Un modèle sûr est :

location /downloads/ {
    alias /srv/downloads/;
    try_files $uri =404;
}

Ici, /downloads/manual.pdf correspond à /srv/downloads/manual.pdf. Sans la discipline de la barre oblique finale, il est facile de construire accidentellement des chemins qui n'existent pas ou d'exposer un répertoire que vous ne vouliez pas publier.

Pour un examen plus approfondi du comportement de correspondance, consultez Blocs d'emplacement Nginx.

Ajoutez des en-têtes de cache navigateur

Les fichiers statiques sont d'excellents candidats pour la mise en cache navigateur. Si un utilisateur télécharge app.css une fois, le navigateur ne devrait pas le récupérer à nouveau à chaque affichage de page, sauf s'il a changé.

Pour les actifs versionnés, utilisez des durées de cache longues :

location /assets/ {
    root /var/www/example.com/public;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Cela fonctionne mieux lorsque les noms de fichiers changent lors du déploiement, comme app.8f3a91.css ou bundle.20260523.js. Si le nom de fichier change lorsque le contenu change, les navigateurs peuvent mettre en cache l'ancien fichier en toute sécurité pendant longtemps.

Pour les fichiers qui conservent le même nom, utilisez une mise en cache plus courte :

location = /index.html {
    root /var/www/example.com/public;
    expires -1;
    add_header Cache-Control "no-cache";
}

Ce modèle est courant pour les applications frontend. Le fichier HTML reste frais, tandis que les fichiers CSS et JavaScript hachés sont mis en cache de manière agressive.

Un exemple pratique : votre build React ou Vue produit des actifs hachés dans /assets/ et un index.html simple. Mettez en cache /assets/ pendant un an, mais faites en sorte que index.html soit revalidé. Les utilisateurs bénéficient de visites répétées rapides, et les nouveaux déploiements chargent toujours les références d'actifs les plus récentes.

Après avoir modifié les règles de cache, testez les en-têtes au lieu de deviner :

curl -I https://example.com/assets/app.8f3a91.css
curl -I https://example.com/

Vous voulez que l'actif haché affiche une valeur Cache-Control de longue durée. Vous voulez généralement que la page HTML soit revalidée ou utilise une courte durée de vie. Si les deux sont mis en cache pendant un an, un déploiement peut laisser les utilisateurs bloqués sur un ancien fichier HTML qui pointe vers un ancien JavaScript.

Utilisez la compression pour les actifs textuels

Les actifs textuels tels que CSS, JavaScript, SVG et JSON se compressent bien. Vous pouvez activer Gzip dans le bloc http :

gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_vary on;
gzip_types
    text/css
    application/javascript
    application/json
    image/svg+xml;

Ne vous attendez pas à ce que Gzip aide beaucoup avec les fichiers JPEG, PNG, WebP, MP4 ou zip. Ces formats sont déjà compressés. Essayer de les compresser à nouveau gaspille généralement du CPU.

Pour les sites statiques à fort trafic, envisagez des fichiers précompressés. Votre processus de build peut créer des versions .gz de gros fichiers CSS et JavaScript, et Nginx peut les servir lorsque le navigateur prend en charge Gzip :

gzip_static on;

Cela réduit le travail de compression à l'exécution car Nginx lit le fichier précompressé depuis le disque. C'est surtout utile lorsque les actifs sont construits à l'avance et ne changent pas entre les requêtes.

La compression n'est qu'une partie de la livraison des actifs. La taille des fichiers compte toujours. Supprimez le JavaScript inutilisé, optimisez les images pendant votre processus de build et évitez d'expédier des fichiers volumineux dont les utilisateurs n'ont pas besoin.

Lorsque vous testez la compression, incluez un en-tête Accept-Encoding :

curl -I -H 'Accept-Encoding: gzip' https://example.com/assets/app.js

Recherchez Content-Encoding: gzip et Vary: Accept-Encoding. L'en-tête Vary est important lorsqu'un CDN ou un cache partagé se trouve devant Nginx, car les réponses compressées et non compressées ne doivent pas être mélangées.

Améliorez la livraison et la sécurité des fichiers

Nginx peut servir des fichiers statiques efficacement avec les paramètres par défaut, mais quelques détails aident en production.

Tout d'abord, désactivez les listes de répertoires sauf si vous en avez explicitement besoin :

autoindex off;

Les listes de répertoires peuvent révéler des noms de fichiers et une structure que vous n'aviez pas l'intention de publier.

Deuxièmement, bloquez l'accès aux fichiers cachés tels que .env, .git et autres fichiers dotfiles :

location ~ /\.(?!well-known) {
    deny all;
}

L'exception pour .well-known est courante car la validation de certificat et les fichiers basés sur des normes peuvent utiliser ce répertoire.

Troisièmement, assurez-vous que les permissions de vos fichiers statiques permettent à Nginx de lire les fichiers mais ne donnent pas au serveur web un accès en écriture inutile. Une configuration typique permet aux outils de déploiement d'écrire des fichiers et à l'utilisateur du worker Nginx de les lire.

Quatrièmement, vérifiez les types MIME. Nginx inclut généralement un fichier mime.types, mais des conteneurs allégés ou des builds personnalisés peuvent le manquer. Si le CSS est servi comme text/plain, les navigateurs peuvent le rejeter ou se comporter différemment.

Utilisez :

include /etc/nginx/mime.types;
default_type application/octet-stream;

Enfin, surveillez les logs pour des réponses 404 répétées sur les actifs. Cela signifie souvent qu'un déploiement a référencé des fichiers qui n'existent pas, qu'un cache pointe toujours vers un ancien nom de fichier ou qu'un chemin alias est erroné.

Si la livraison statique semble lente, ne commencez pas par copier toutes les directives d'optimisation que vous pouvez trouver. Vérifiez d'abord si le problème vient réellement de Nginx. Les grandes images, les bundles frontend non optimisés, les montages de stockage distant et les absences de cache CDN sont des causes plus courantes qu'une micro-optimisation manquante dans le bloc serveur.

Pour une vérification locale rapide :

curl -o /dev/null -s -w 'status=%{http_code} size=%{size_download} time=%{time_total}\n' https://example.com/assets/app.js

Comparez ensuite cela avec les logs CDN, les outils de développement du navigateur ou une requête depuis la même région que vos utilisateurs. Une réponse rapide de Nginx et une réponse lente dans le navigateur pointent généralement ailleurs dans le chemin de livraison.

Quand demander de l'aide

Faites appel à un ingénieur DevOps si vos fichiers statiques sont servis depuis un stockage partagé, des volumes montés, des passerelles de stockage objet ou un CDN devant Nginx. La meilleure stratégie de mise en cache dépend de l'ensemble du chemin de livraison, pas seulement du bloc serveur Nginx.

Vous devriez également demander de l'aide si les utilisateurs signalent du JavaScript obsolète après les déploiements. Cela signifie généralement que les règles de cache et la stratégie de versionnement des noms de fichiers ne correspondent pas.

Servir des fichiers statiques avec Nginx fonctionne mieux lorsque les chemins sont prévisibles, les durées de cache correspondent à la stratégie de nommage des fichiers et les actifs textuels sont compressés. Gardez les fichiers manquants visibles, protégez les fichiers cachés et testez les en-têtes après chaque changement de configuration. Une configuration statique propre rend votre site plus rapide sans ajouter de pièces mobiles.