Retour au cours

infra / nginx

Compression : gzip et brotli

Leçon 81 exercice

Explication

Ce que vous allez apprendre

  • Activer gzip pour compresser les réponses textuelles avant envoi au client
  • Comprendre pourquoi seuls certains types de contenu doivent être compressés
  • Ajouter brotli en complément de gzip pour un meilleur taux de compression
  • Vérifier depuis le terminal qu'une compression est effectivement appliquée
  • Pré-générer les fichiers compressés en CI/CD pour éliminer le coût CPU au runtime

Dans quel contexte ?

Une application web sert un fichier JavaScript de 800 Ko à chaque premier chargement de page. Sans compression, chaque visiteur télécharge ces 800 Ko intégralement ; avec une compression texte efficace, ce même fichier peut descendre à 150-200 Ko réellement transférés, sans qu'aucun octet du fichier source n'ait changé sur le disque.

D'abord, gzip est la solution la plus simple à activer

gzip est intégré nativement à Nginx : aucune installation ni compilation supplémentaire n'est nécessaire, il suffit de l'activer dans la configuration. C'est pour cette raison qu'il reste, encore aujourd'hui, la compression la plus largement déployée sur le web, malgré l'existence d'alternatives plus performantes.

Une fois gzip activé, une question se pose immédiatement : que faut-il compresser ?

Seul le contenu textuel (JSON, JavaScript, CSS, SVG, HTML) bénéficie réellement de la compression : ces formats contiennent beaucoup de répétitions que l'algorithme peut exploiter. Les formats déjà compressés (images JPEG/PNG, vidéos MP4, archives ZIP) ne gagnent presque rien à être recompressés, et le CPU dépensé pour l'essayer est du gaspillage pur.

Type de contenuFaut-il compresser ?Raison
JSON, JS, CSS, SVG, HTMLOuiBeaucoup de répétitions, gain important
JPEG, PNG, MP4, ZIPNonDéjà compressés, gain quasi nul, CPU gaspillé

Ensuite, une alternative plus moderne mais moins universelle : brotli

Brotli, développé par Google, atteint généralement un meilleur taux de compression que gzip à qualité équivalente, au prix d'un calcul plus lent en compression dynamique. Contrairement à gzip, il nécessite un module additionnel (libnginx-mod-http-brotli sur Debian/Ubuntu récents), ce qui explique qu'il ne soit pas activé par défaut partout.

Prérequis

Cette leçon suppose que tu es à l'aise avec les blocs http {} et location {} (leçons 2 et 3) : les directives de compression peuvent s'appliquer à ces deux niveaux.

Il reste un choix de stratégie pour la production : compresser à la volée ou à l'avance ?

Compresser dynamiquement à chaque requête consomme du CPU serveur en continu. Une alternative "niveau expert" consiste à pré-générer les fichiers .gz et .br au moment du build (en CI/CD), puis à les servir directement avec gzip_static on; et brotli_static on; : Nginx sert alors le fichier déjà compressé sans aucun calcul au runtime.

Bonne pratique

Pour des assets statiques versionnés (JS/CSS buildés), préfère systématiquement la compression pré-générée en CI/CD (gzip_static/brotli_static) plutôt que la compression dynamique : le coût CPU passe de "à chaque requête" à "une seule fois au moment du build", un gain net à trafic élevé.

Piège fréquent

Activer gzip avec un gzip_comp_level très élevé (proche de 9) sur du contenu généré dynamiquement à fort trafic peut créer une charge CPU inattendue sur le serveur Nginx lui-même : le niveau 6, souvent recommandé par défaut, est déjà un bon compromis entre taux de compression et consommation CPU.

Maintenant que le trafic est à la fois chiffré et compressé, la prochaine leçon aborde une protection différente, orientée sécurité et disponibilité : le rate limiting, pour se protéger des pics de trafic et des abus.

Commandes & code

Compression : gzip et brotli

nginx
# gzip : intégré nativement à Nginx, aucune compilation supplémentaire nécessaire
http {
    gzip on;
    gzip_vary on;                     # ajoute "Vary: Accept-Encoding" (cache correct par proxys/CDN)
    gzip_proxied any;                 # compresse même les réponses provenant d'un proxy_pass
    gzip_comp_level 6;                # 1 (rapide, peu compressé) à 9 (lent, très compressé) — 6 = bon compromis
    gzip_min_length 256;              # inutile de compresser des réponses minuscules (overhead CPU > gain)

    gzip_types
        text/plain
        text/css
        text/xml
        application/json
        application/javascript
        application/xml+rss
        image/svg+xml;
    # NE PAS compresser : jpg/png/mp4/zip (déjà compressés, la re-compression gaspille du CPU pour rien)
}
nginx
# brotli : meilleur taux de compression que gzip, mais nécessite le module ngx_brotli (souvent à compiler ou via package)
# Sur Debian/Ubuntu récents : apt install libnginx-mod-http-brotli

http {
    brotli on;
    brotli_comp_level 5;              # 0-11 ; niveau 5-6 = bon compromis CPU/ratio en dynamique
    brotli_types
        text/plain
        text/css
        application/json
        application/javascript
        image/svg+xml;

    # Stratégie courante : brotli pour les navigateurs qui le supportent, gzip en fallback
    # -> Nginx gère automatiquement la négociation via le header Accept-Encoding du client
}
bash
# Vérifier la compression effective depuis le terminal
curl -H "Accept-Encoding: gzip, br" -sI https://example.com/app.js | grep -i content-encoding
# content-encoding: br      (ou gzip si brotli non actif)

# Comparer les tailles
curl -s https://example.com/app.js | wc -c                        # taille non compressée reçue par curl
curl -s -H "Accept-Encoding: gzip" https://example.com/app.js | wc -c   # taille compressée
nginx
# Compression statique pré-générée (gzip_static) : évite de compresser à chaque requête (CPU = 0 au runtime)
location ~* \.(js|css)$ {
    gzip_static on;      # sert directement app.js.gz s'il existe à côté de app.js
    brotli_static on;    # idem pour app.js.br

    expires 1y;
    add_header Cache-Control "public, immutable";
}
bash
# Générer les fichiers .gz et .br au moment du build (CI/CD), plutôt qu'à la volée
gzip -9 -k dist/app.js          # -k = garde l'original, crée app.js.gz
brotli -q 11 -k dist/app.js     # -q 11 = qualité max, crée app.js.br

Résumé

  • gzip est intégré nativement ; brotli nécessite un module additionnel mais compresse mieux à taille égale.
  • Ne compresser QUE le texte (JSON, JS, CSS, SVG) : jamais des formats déjà compressés (images, vidéos, zip).
  • gzip_static/brotli_static + pré-génération en CI/CD élimine le coût CPU de compression au runtime — approche "niveau expert".

Exercices pratiques

1 disponible
1

Mission : réduire la charge CPU d'un site qui recompresse à chaque requête

Objectif : Diagnostiquer une surcharge CPU liée à la compression dynamique et migrer vers une compression statique pré-générée en CI/CD.

Contexte

Un site sert app.js (800 Ko) à fort trafic. La configuration actuelle utilise gzip_comp_level 9; en compression dynamique, et le monitoring montre un CPU Nginx anormalement élevé aux heures de pointe. L'équipe veut aussi compresser les images du site pour 'gagner encore plus de place'.

Résoudre l’exercice →