CDN : mise en place et optimisation pour vos applications web
Réduire la latence et tenir une disponibilité géographique : deux défis pour toute application web. Quand un utilisateur en Bretagne attend le serveur d'origine situé en région parisienne, la performance s'effondre. Le Content Delivery Network (CDN) répond à ce problème. En cachant vos contenus aux points de présence (PoPs) distribués, un CDN divise par 3 ou 4 le temps de réponse et soulage votre infrastructure.
Ce guide couvre le déploiement pratique d'un CDN, la configuration des headers, les stratégies d'invalidation, et les pièges à éviter pour intégrer le CDN à votre stack existant.
Plan de l'article
- Comment fonctionne un CDN
- Quand utiliser un CDN
- Configuration des headers de cache
- Stratégies d'invalidation
- CDN et architecture multi-couches
- Nginx comme couche locale de cache
- Monitoring et observabilité
- HTTPS et sécurité au CDN
- Pièges courants
- Conclusion
Comment fonctionne un CDN
Un CDN repose sur trois composants :
Les edge servers (serveurs de périphérie) Situés dans des datacenters répartis mondialement (ou au minimum nationalement pour un CDN français), ils interceptent les requêtes des utilisateurs finaux et servent le contenu depuis leur cache local.
La hiérarchie de cache Chaque requête suit ce parcours : utilisateur → edge → mid-tier (optionnel) → shield (optionnel) → origin. Cette pyramide répartit la charge et réduit le coût de bande passante vers l'origine.
L'origin server Votre serveur réel (Nginx, Apache, app backend, etc.). Lui seul dispose de la version canonique du contenu. Une montée en charge mal gérée sur l'origin révèle immédiatement l'impact du CDN.
Quand utiliser un CDN ?
Assets statiques : images, CSS, JavaScript, fonts. Cas d'usage classique.
API public : GET-only, réponses déterministes. Un CDN peut cacher des réponses JSON et réduire la charge de votre backend.
HTML pages : moins courant mais utile si votre HTML est stable (blogs, documentation). Exige une stratégie TTL courte.
Streaming vidéo/audio : le CDN décharge la quasi-totalité du coût de bande passante.
Cas où un CDN n'aide PAS : contenu personnalisé (pages utilisateur loggées), POST requests, websocket, contenu temps réel strictement < 1 seconde.
Configuration des headers de cache
Les headers HTTP dictent le comportement du CDN. Maîtrisez-les, vous gagnez en hit ratio et en temps de réponse.
Cache-Control
Cache-Control: public, max-age=86400, immutable
public: le CDN peut cacher (contrairement àprivate, réservé aux navigateurs)max-age=86400: durée de validité en secondes (ici 24h)immutable: le CDN oublie rarement ce header même après expiration
Pour un asset versionnné (ex: bundle.abc123.js), utilisez max-age=31536000, immutable (1 an).
Surrogate-Control (CDN spécifique)
Surrogate-Control: max-age=3600, stale-while-revalidate=86400
Autorise le CDN à servir du contenu "rassis" jusqu'à 24h le temps de revalider en arrière-plan. Indispensable pour masquer les pics de latence d'origine.
Vary
Vary: Accept-Encoding, Accept-Language
Force le CDN à créer des entrées séparées pour chaque valeur de ces headers. Attention : trop de variations fragmentent le cache (hit ratio baisse).
ETag et Last-Modified
ETag: "w/5d2-18e89a69"
Last-Modified: Wed, 15 Jan 2025 10:00:00 GMT
Déclenchent la revalidation 304 Not Modified. Très utile pour le contenu semi-statique (blog).
stale-while-revalidate
Cache-Control: max-age=300, stale-while-revalidate=3600
Le CDN sert du cache expiré (300s) pendant qu'il demande l'origin en arrière-plan (jusqu'à 3600s d'attente tolérance).
Stratégies d'invalidation
Cacher, c'est bien. Savoir invalider, c'est critique.
TTL classique
Repose sur l'expiration naturelle. Simple, aucun risque de servir du vieux contenu en production. Mais : attend le TTL si correction urgente.
assets statiques : max-age=31536000 (versionnés)
pages HTML : max-age=3600
API : max-age=300
Purge immédiate
La plupart des CDN exposent une API purge. Exemples Cloudflare, Bunny CDN, AWS CloudFront.
curl -X POST https://api.example-cdn.com/purge \
-H "Authorization: Bearer token" \
-d '{"paths": ["/images/logo.png", "/api/users/*"]}'
Risque : sur-utilisation = limitation de débit API.
URLs versionnées
Au lieu de modifier /app.js, générez /app.abc123def456.js à chaque déploiement. Le CDN cache à vie ; les anciennes URLs expirent naturellement.
Framework bundler recommandé : Webpack, Vite, esbuild détectent les changements et renomment automatiquement.
Tag-based purge
Associez des tags à chaque asset :
Content-Surrogate-Key: prod, homepage, v2.1.0
Puis invalidez par tag :
curl -X POST purge \
-H "Surrogate-Key-Purge: v2.1.0"
Très utile pour les déploiements atomiques.
CDN et architecture multi-couches
Une vraie infrastructure CDN comporte plusieurs étages :
User Request
↓
[Edge Servers] ← Cache Hit (90%+ des cas)
↓ Cache Miss
[Shields / Mid-tier] ← Agrège les requêtes redondantes
↓ Cache Miss
[Origin] ← Votre serveur
Pull vs Push :
- Pull : CDN demande l'origin à la demande (standard)
- Push : vous versez pré-activement le contenu aux edges (couteux, mais zéro latence initiale)
Failover : si origin craque, certains CDN peuvent servir du stale content indéfiniment. À configurer selon votre RTO.
Nginx comme couche locale de cache
Si vous hébergez votre origin chez vous ou avez besoin d'une couche cache avant le CDN (pour déduplication), Nginx est une solution légère.
Configuration de base
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m
max_size=1g inactive=60m use_temp_path=off;
upstream backend {
server app.local:8000;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_cache my_cache;
proxy_pass http://backend;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 1h;
proxy_cache_valid 404 10m;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_bypass $http_cache_control;
add_header X-Cache-Status $upstream_cache_status;
}
}
Points clés :
keys_zone: nom et taille (ici 10 MB en mémoire, répertoire /var/cache/nginx pour le disque)proxy_cache_use_stale: sert du contenu expiré si backend en erreurX-Cache-Status: header custom pour déboguer (HIT/MISS/BYPASS)
Cache warming
Pré-remplissez le cache Nginx avec une simple boucle au démarrage :
#!/bin/bash
while IFS= read -r url; do
curl -s "$url" > /dev/null
done < /tmp/urls_to_warm.txt
Monitoring CDN
Ne laissez jamais un CDN sans observabilité.
Métriques critiques :
- Cache Hit Ratio : % requêtes servies depuis cache. Cible : 80 %+ pour assets, 60 %+ pour API.
- Bandwidth savings : bande passante économisée (origin utilisation réduite).
- Origin offload : % du traffic absorbé par CDN (doit être 95 %+).
- Latency percentiles : p50, p95, p99. Le CDN doit avoir p95 < 100 ms depuis France.
Dashboards recommandés
Utiliser Grafana + Prometheus, ou les outils natifs du CDN :
# Prometheus
- job_name: 'cdn_metrics'
static_configs:
- targets: ['api.cdn.local:9090']
Alertez sur :
- hit ratio < 70 % (cache dégradé)
- origin bandwidth > seuil normal
- latency p99 > 1000ms
CDN et HTTPS
Tout CDN moderne gère HTTPS en transparence.
TLS Termination : le CDN chiffre user ↔ edge, puis origin ↔ edge (http ou https selon config).
HTTP/2 et HTTP/3 : les bons CDN poussent HTTP/2 par défaut, HTTP/3 (QUIC) pour les clients modernes. Latence en baisse, throughput en hausse.
Certificate Management : le CDN auto-renouvelle vos certificats (Lets Encrypt gratuit). Aucune action requise.
Conseils :
- Activez HSTS (Strict-Transport-Security)
- Refusez explicitement HTTP (redirect 301 vers HTTPS)
- Utilisez des certificats wildcard si multi-domaine
Pièges courants
1. Cache poisoning
Un attaquant envoie une requête malveillante (X-Forwarded-For: fake, Host: attacker.com) qui contamine le cache global. Mitigation : ne cachez jamais sur headers non-contrôlés.
# ❌ Mauvais
proxy_cache_key "$host$request_uri$http_x_forwarded_for";
# ✓ Bon
proxy_cache_key "$http_host$request_uri";
2. Stale content après déploiement
Vos utilisateurs voient l'ancienne version 48h après un deploy. Cause : TTL élevé sans versioning. Solution : versionnez les URLs ou déclenchez purge API au deploy.
3. Cookie-based caching
Un CDN cacherait une réponse Set-Cookie destinée à un utilisateur, puis la servirait à un autre. Catastrophe.
Cache-Control: private, max-age=0 /* ← Obligatoire si cookies */
4. CORS et CDN
Les headers Access-Control-* doivent être cachés par domaine demandeur. Sinon le premier visiteur depuis domainA décide pour tous les autres.
proxy_cache_key "$scheme$request_method$host$request_uri$http_origin";
5. Origin bottleneck
Le CDN fonctionne bien, mais origin craque. Avant de pointer 10 000 utilisateurs au CDN, vérifiez que origin absorbe le traffic miss.
Perspectives complémentaires
Pour approfondir :
- Optimiser Nginx et le cache côté serveur : approche complémentaire sans CDN externe
- Varnish Cache : architecture haute performance : alternative légère à un CDN pour infra interne
- Nginx + Varnish : déduplication multi-layer : combiner les deux
- Core Web Vitals et SEO : CDN améliore LCP et FID
- Optimiser le temps de chargement d'un site : stratégie globale
- HTTP/3 et performance : bénéfices du protocole moderne
Infrastructure et CDN
Rappel : un CDN ne remplace pas une infrastructure stable. Le CDN accélère l'arrivée du contenu au client ; l'infrastructure d'origine doit tenir le retour vers vos données, y compris sur les requêtes en cache miss et sur le failover.
Sources
- Cloudflare, "How do Content Delivery Networks (CDNs) work ?", https://www.cloudflare.com/en-gb/learning/cdn/what-is-a-cdn/
- Nginx, "Module ngx_http_proxy_module", https://nginx.org/en/docs/http/ngx_http_proxy_module.html
- RFC 7234, "HTTP Caching", https://tools.ietf.org/html/rfc7234
- OWASP, "Cache Poisoning Attacks", https://owasp.org/www-community/attacks/Cache_Poisoning
- MDN Web Docs, "HTTP Caching", https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
- HTTP Working Group, "HTTP/2 Specifications", https://http2.github.io/
Conclusion
Déployer un CDN n'a rien de trivial : il faut comprendre les headers HTTP, régler les TTLs, prévoir l'invalidation, et monitorer en continu. Les erreurs les plus fréquentes viennent d'une mauvaise compréhension de la hiérarchie cache et des pièges de sécurité.
Cette configuration, couplée à une infrastructure stable et à une stratégie de versioning, sert vos utilisateurs 3 à 5× plus vite tout en réduisant la charge de vos serveurs d'origine.
Si les cache miss et le failover vers l'origine reposent sur un transit IP que vous ne maîtrisez pas, c'est là que le maillon faible se loge.
À vous de jouer !


