VPSSPark Blog
← Retour au journal

Éliminer les goulots de bande passante serveur : tuning Nginx reverse proxy en pratique

Notes serveur · 2026.07.22 · ~14 min de lecture

Recherches fréquentes : tuning Nginx reverse proxy · bande passante serveur · gzip · proxy_cache

Baies serveurs et commutateurs réseau—reverse proxy Nginx et optimisation bande passante
Les goulots de bande passante sont souvent un problème de configuration, pas de CPU.

Le mois dernier, nous avons dépanné un client SaaS : VPS 2 vCPU / 4 Go, CPU autour de 20 %, et chaque après-midi à 15 h le site devenait un diaporama. Sur le monitoring cloud, la bande passante sortante touchait le plafond — 100 Mbps saturés pendant quarante minutes d’affilée. Sa première réaction : « Il faut upgrader. » Nous avons ouvert les logs d’accès Nginx : 70 % du trafic venait de réponses API JSON non compressées et de JS statiques avec des paramètres ?v= aléatoires — les mêmes ressources renvoyées en entier à chaque fois.

Après Gzip, en-têtes de cache statique et upstream keepalive, le pic est tombé à 35 Mbps, le chargement de 8 à 1,2 seconde, sans dépenser un centime de plus. Sur les petits VPS, c’est classique : le goulot, c’est la bande passante sortante, pas le CPU. Nginx en reverse proxy entre utilisateurs et backend est le meilleur levier pour économiser la bande passante — à condition de savoir quelles vis tourner.

Cet article n’est pas un guide d’installation Nginx, mais une checklist d’optimisation orientée bande passante validée en production : diagnostiquer, compresser, mettre en cache, puis optimiser la réutilisation des connexions et le buffering. Prérequis : Nginx en reverse proxy HTTPS sur le port 443 (sans pare-feu, commencez par notre guide UFW pour serveur cloud — ouvrir 22/80/443, puis optimiser).

~65 %
Réduction JSON typique après Gzip
4 étapes
Diagnostic→Compression→Cache→Connexion
0 €
La plupart des optimisations sans upgrade

Pourquoi la bande passante sature avant le CPU ?

Sur un VPS cloud, la bande passante facturée est souvent asymétrique : petits forfaits à 100 Mbps de pic et 1–2 To/mois — ça paraît confortable, mais une API JSON non compressée de 500 Ko à 200 req/s représente théoriquement 800 Mbps et fait sauter la limite. Nginx sert fichiers statiques et reverse proxy simple avec peu de CPU — d’où le tableau habituel : « CPU au repos, bande passante pleine ».

Autre piège : tout envoyer à l’origine. Sans CDN, sans cache navigateur, sans proxy_cache, chaque utilisateur retélécharge bundle.js et logo.png à chaque refresh. Les modules http de la documentation officielle Nginx servent surtout à transmettre moins d’octets ou ouvrir moins de connexions — l’enjeu est de les combiner selon le scénario, pas de copier une config universelle.

Optimisation bande passante Nginx reverse proxy en quatre étapes : diagnostic, compression, cache, réutilisation des connexions
Commencez par le gratuit (gzip, expires, keepalive), puis CDN ou upgrade de bande passante.
Symptôme Cause fréquente Action prioritaire
API lente, bande passante élevée JSON/HTML non compressés Activer gzip / brotli
Gros trafic au rechargement Assets statiques sans Cache-Control expires + noms avec empreinte
Connexions backend en hausse Nouveau TCP upstream par requête Pool keepalive
Gros téléchargements saturent la sortie Origine directe, pas de cache segmenté CDN ou proxy_cache

Étape 1 : diagnostiquer avant d’upgrader à l’aveugle

Avant de toucher à la config, dix minutes pour savoir où part la bande passante. Sur le serveur, nous utilisons souvent :

Diagnostic bande passante et connexions
# Trafic en direct par connexion (apt install iftop)
                sudo iftop -i eth0

                # Stats horaires/journalières (vnstat)
                vnstat -h
                vnstat -d

                # Logs d'accès Nginx : URLs les plus volumineuses
                awk '{print $7, $10}' /var/log/nginx/access.log | \
                  awk '{a[$1]+=$2} END {for(i in a) print a[i], i}' | sort -rn | head -20

                # Connexions ESTABLISHED actuelles
                ss -s
                ss -tn state established | wc -l

Si /api/ domine avec des corps de plusieurs centaines de Ko, la compression est la priorité. Si ce sont .js, .css, .woff2 toujours en 200 (pas de 304), les en-têtes de cache manquent. Distinguez entrant et sortant : DDoS ou crawlers saturent l’entrée — autre sujet (limitation, WAF, fail2ban). Ici, on vise l’optimisation sortante en conditions normales.

Les graphiques cloud agrègent avec 1–5 minutes de retard ; au dépannage, iftop sur la machine fait foi. Si SSH rame, consultez notre guide de dépannage SSH refusé sur serveur Linux pour écarter un problème réseau.

Étape 2 : Gzip / Brotli — la réduction la moins chère

Les réponses texte (JSON, HTML, JS, CSS, SVG, XML) se compressent typiquement de 60 à 80 %. Le module gzip intégré ne demande que quelques lignes ; la charge CPU reste acceptable sur la plupart des VPS.

/etc/nginx/nginx.conf ou conf.d/gzip.conf
gzip on;
                gzip_vary on;
                gzip_proxied any;
                gzip_comp_level 5;          # 6–9 : rendements décroissants, 5 est le bon compromis
                gzip_min_length 256;        # Ne pas compresser les petites réponses
                gzip_types
                    text/plain
                    text/css
                    text/javascript
                    application/javascript
                    application/json
                    application/xml
                    image/svg+xml
                    font/woff2;

En pratique : gzip_proxied any compresse aussi le contenu proxifié (par défaut, seules les réponses directes). Ne gzip pas JPEG/PNG/WebP ni la vidéo — binaire déjà compressé, CPU gaspillé. Vérifiez avec curl -H 'Accept-Encoding: gzip' -I https://your.site/api/foo la présence de Content-Encoding: gzip.

Avec le module Brotli (certaines distros ou builds maison), 15–20 % de gain supplémentaire à qualité égale — idéal pour les API textuelles. Sans module, un gzip stable suffit largement.

HTTPS et vieux clients
Quelques clients très anciens gèrent mal gzip en HTTPS ; les navigateurs modernes, non. Pour du matériel embarqué préhistorique, désactivez gzip par User-Agent — en 2026, c’est rarement nécessaire.

Étape 3 : cache des assets statiques et sendfile

Les outils de build (Vite, Webpack) ajoutent un hash au nom de fichier, ex. app.a3f2b1.js. Ces fichiers peuvent être mis en cache longtemps — la deuxième visite ne les retélécharge pas. Beaucoup d’équipes hashent côté build mais n’envoient pas Cache-Control depuis Nginx : le navigateur redemande tout à chaque fois.

Exemple location pour assets statiques
location ~* \.(js|css|woff2?|ttf|ico|svg)$ {
                    root /var/www/app/dist;
                    expires 30d;
                    add_header Cache-Control "public, immutable";
                    access_log off;           # Couper access_log sur cache hit pour moins d'IO
                }

                # Recommandé dans le bloc http
                sendfile on;
                tcp_nopush on;
                tcp_nodelay on;

sendfile envoie les pages fichier du noyau directement vers le socket, moins de copies userspace — utile pour gros fichiers et téléchargements concurrents. Testez si vous combinez AIO ou pools de threads ; pour la plupart des sites, sendfile + tcp_nopush + tcp_nodelay suffisent.

Pas de immutable sur HTML et index.html, sinon les utilisateurs gardent l’ancienne coque après déploiement. Stratégie courante : assets hashés 30 jours, HTML en no-cache (revalidation autorisée).

Étape 4 : cache reverse proxy (proxy_cache)

Pour les API surtout en lecture (listes de config, catalogues, détails d’article), un cache court côté Nginx divise la bande passante origine par le taux de succès. L’une des capacités les plus sous-estimées du module proxy.

Configuration de base proxy_cache
# bloc http
                proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=apicache:50m
                                 max_size=2g inactive=60m use_temp_path=off;

                upstream backend {
                    server 127.0.0.1:3000;
                    keepalive 32;              # voir section suivante
                }

                server {
                    location /api/ {
                        proxy_pass http://backend;
                        proxy_http_version 1.1;
                        proxy_set_header Connection "";

                        proxy_cache apicache;
                        proxy_cache_valid 200 5m;
                        proxy_cache_key "$scheme$request_method$host$request_uri";
                        add_header X-Cache-Status $upstream_cache_status;

                        proxy_buffering on;
                        proxy_buffers 16 16k;
                        proxy_busy_buffers_size 64k;
                    }
                }

$upstream_cache_status affiche HIT, MISS ou BYPASS — le cache est-il actif ? Les écritures (POST/PUT/DELETE) doivent contourner le cache ; les API personnalisées avec cookies demandent prudence pour ne pas servir les données de A à B.

Avec proxy_buffering on, Nginx absorbe la réponse backend avant de l’envoyer au client — backend lent, client rapide : moins de connexions bloquées. Pour SSE ou gros uploads : proxy_buffering off sur la location concernée.

Étape 5 : upstream keepalive — moins de poignées de main TCP

Par défaut, Nginx peut ouvrir une nouvelle TCP vers le backend à chaque requête client. À forte QPS, TIME_WAIT et handshakes consomment CPU et ports locaux — réponses plus lentes, débit effectif en baisse. upstream keepalive maintient un pool de connexions réutilisables après chaque réponse.

keepalive — le trio indispensable
upstream backend {
                    server 127.0.0.1:8080;
                    keepalive 64;               # taille du pool selon la QPS
                }

                location / {
                    proxy_pass http://backend;
                    proxy_http_version 1.1;     # HTTP/1.1 requis pour keepalive
                    proxy_set_header Connection "";  # supprimer Connection: close
                }

Sans proxy_http_version 1.1 ou Connection "", keepalive ne fonctionne pas — le cas le plus fréquent de « configuré pour rien » chez nos clients. keepalive 64 convient en dessous d’un million de PV/jour ; trop grand surcharge les descripteurs côté backend.

Étape 6 : workers, connexions et limitation de débit

Bande passante pleine : vérifier que Nginx n’est pas lui-même le goulot de connexions. Paramètres clés en tête de nginx.conf :

Workers et connexions (VPS 2 vCPU)
worker_processes auto;
                worker_rlimit_nofile 65535;

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

                # Optionnel : limiter par IP pour éviter qu'un client monopolise
                limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
                limit_conn_zone $binary_remote_addr zone=conn:10m;

                server {
                    limit_req zone=perip burst=20 nodelay;
                    limit_conn conn 50;
                }

worker_connections × worker_processes doit dépasser le pic de connexions. Sur 2 cœurs, worker_processes auto donne souvent 2 — 4096 × 2 = 8192 largement suffisant pour PME. Alignez fs.file-max et worker_rlimit_nofile, sinon too many open files dans les logs.

limit_rate bride un téléchargement ; limit_req protège les API. Ça n’« augmente » pas la bande passante, mais empêche quelques flux anormaux de pénaliser tout le monde — dernière barrière de gouvernance.

Étape 7 : quand passer au CDN ?

Optimisations faites et bande passante encore au plafond de façon cyclique : CDN ou forfait supérieur. Critères simples :

  • Assets statiques > 60 % du trafic sortant → CDN pour JS/CSS/images, origine pour HTML et API seulement
  • Utilisateurs multi-régions → nœuds edge raccourcissent la distance et soulagent l’origine
  • Pics (campagnes, live) → le CDN absorbe les pointes, pas besoin d’acheter la bande passante au pic sur l’origine

Avec un CDN, côté Nginx : origine accessible uniquement aux IP du CDN (liste blanche pare-feu) et IP client réelle transmise (X-Forwarded-For / module real_ip). Sinon un attaquant contourne protection et cache en frappant l’IP origine directement.

Exemple complet de bloc server (à adapter et déployer)

Tous les fragments réunis en exemple minimal — backend Node / Python sur 127.0.0.1:3000 :

/etc/nginx/sites-available/app.conf
upstream app {
                    server 127.0.0.1:3000;
                    keepalive 32;
                }

                server {
                    listen 443 ssl http2;
                    server_name app.example.com;

                    ssl_certificate     /etc/letsencrypt/live/app.example.com/fullchain.pem;
                    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

                    gzip on;
                    gzip_types application/json application/javascript text/css text/plain;
                    gzip_min_length 256;

                    location /assets/ {
                        alias /var/www/app/dist/assets/;
                        expires 30d;
                        add_header Cache-Control "public, immutable";
                        access_log off;
                    }

                    location / {
                        proxy_pass http://app;
                        proxy_http_version 1.1;
                        proxy_set_header Host $host;
                        proxy_set_header X-Real-IP $remote_addr;
                        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                        proxy_set_header X-Forwarded-Proto $scheme;
                        proxy_set_header Connection "";
                    }
                }

Puis sudo nginx -t && sudo systemctl reload nginx et onglet Network du navigateur : cache 30 jours sur les assets, gzip sur les API. Dans notre checklist de release : curl -sI https://app.example.com/assets/main.js | grep -i cache.

Validation et surveillance continue

L’optimisation n’est pas ponctuelle. Dans Grafana ou monitoring cloud, suivez quatre courbes : bande passante sortante, connexions actives Nginx, temps de réponse upstream, taux de succès cache (si proxy_cache). Avant release ou pic de trafic, test de charge : ab -n 1000 -c 50 https://app.example.com/ ou hey -n 5000 -c 100 — comparez pic de bande passante et latence P95 avant/après.

Bande passante en baisse mais latence toujours haute : le goulot est peut-être la base ou le disque — autre chapitre. Au moins vous savez : investir dans les index, pas acheter 500 Mbps à l’aveugle.

En une phrase
iftop pour les gros consommateurs, gzip sur le texte, expires sur le statique, keepalive vers le backend ; proxy_cache pour les API en lecture ; CDN si ce n’est pas suffisant. La plupart des problèmes de bande passante VPS sont une question de config, pas de matériel.

Au-delà du tuning : le bon nœud économise aussi la bande passante

Nginx réduit les octets envoyés, mais pas la distance physique utilisateur–origine. Public APAC sur un VPS US Est : RTT élevé, retransmissions, débit effectif réduit. Beaucoup d’équipes placent build et preview sur Mac cloud ou nœuds proches, statique via stockage objet + CDN, origine réservée aux API — la facture bande passante s’en remercie.

Le Mac mini M4 VPSSPark en cloud convient au CI, previews internes et bastion : macOS natif, Terminal et OpenSSH prêts ; veille ~4 W, idéal 7×24 en relais ou machine de build, plus sobre qu’un petit x86. Avec UFW sur 443 seulement et apps sur 127.0.0.1, surface d’attaque et gaspillage de bande passante diminuent.

Si vous concevez une architecture économe en bande passante et simple à opérer, le Mac mini cloud VPSSPark est un choix pragmatique comme nœud bastion et build basse consommation voir les offres — pour que votre tuning Nginx ne soit pas annulé par un mauvais choix de région.

Offre limitée

Bande passante optimisée—le nœud doit suivre

Mac mini basse consommation · bastion Unix natif · silencieux 24/7

Accueil
Offre limitée Voir les offres