Objectif
Limiter les abus, boucles clientes et pics de trafic sur une API en choisissant une clé de quota adaptée, en mesurant d’abord le trafic réel, en déployant progressivement la limitation et en distinguant clairement limitation de débit, authentification et protection anti-DDoS.
Prérequis
- Trafic API mesuré : requêtes/s habituelles, pics, endpoints les plus sollicités et clients critiques.
- Reverse proxy ou API gateway identifié et configuration versionnée.
- Clé de quota choisie avec compréhension des proxies/NAT et de l’authentification.
- Code de réponse attendu, généralement 429 pour Too Many Requests lorsque la plateforme le permet.
- Plan de test avec client normal, rafale contrôlée et mécanisme de rollback.
Procédure pas à pas
Mesurer le trafic avant de fixer un seuil
Collectez au moins plusieurs périodes représentatives. Analysez p50/p95/p99 de requêtes par seconde par client et par endpoint, puis distinguez les appels interactifs des traitements batch. Un seuil raisonnable doit protéger la plateforme sans casser les clients légitimes. Documentez aussi les endpoints coûteux qui méritent un quota différent.
- Le seuil proposé est dérivé de données réelles et non d’une valeur générique.
Choisir la bonne clé de limitation
Pour une API publique non authentifiée, l’IP peut être un premier signal. Pour une API authentifiée, une clé API, un tenant ou un identifiant de client est souvent plus juste. Si NGINX limite par IP, $binary_remote_addr économise de l’espace dans la zone. Derrière un load balancer, configurez d’abord l’adresse réelle de manière sûre.
- La clé ne regroupe pas involontairement tous les utilisateurs derrière un même proxy.
Créer une zone NGINX en mode observation
Dans NGINX, limit_req_zone définit une zone mémoire et un taux. Commencez avec limit_req_dry_run on afin de compter les requêtes qui auraient été retardées ou rejetées sans les bloquer. Choisissez un nom de zone explicite et placez la directive au niveau http. Testez la configuration avant reload.
limit_req_zone $binary_remote_addr zone=api_per_ip:10m rate=10r/s;
nginx -t
- La configuration est syntaxiquement valide et aucune requête n’est encore bloquée.
Appliquer le dry-run à l’endpoint pilote
Ajoutez limit_req sur un endpoint précis, avec un burst correspondant aux rafales légitimes. En dry-run, NGINX expose l’état via $limit_req_status et journalise les excès selon le niveau configuré. Ne commencez pas par toute l’API si les usages sont hétérogènes.
location /api/v1/ {
limit_req zone=api_per_ip burst=20 nodelay;
limit_req_dry_run on;
limit_req_log_level notice;
proxy_pass http://api_backend;
}
nginx -t && nginx -s reload
- Le trafic continue normalement mais les excès potentiels deviennent mesurables.
Analyser les résultats dry-run
Pendant la période pilote, mesurez PASSED, DELAYED_DRY_RUN et REJECTED_DRY_RUN dans vos logs ou métriques. Identifiez les clients légitimes qui dépasseraient le seuil et déterminez pourquoi : batch prévu, retry agressif, client partagé ou bug. Ajustez rate/burst ou créez une classe de quota distincte plutôt que d’augmenter globalement le seuil.
- Les faux positifs sont compris avant activation réelle.
Choisir burst, délai et code de rejet
burst autorise une file de requêtes excédentaires ; nodelay permet de consommer la rafale sans les étaler. Pour une API, choisissez selon le comportement du client et la latence acceptable. NGINX renvoie 503 par défaut lors d’un rejet ; définissez limit_req_status 429 si vous voulez un signal API standard et si vos clients savent gérer ce code.
limit_req_status 429;
- La politique de rafale et le code de rejet sont documentés pour les développeurs clients.
Activer la limitation sur le périmètre pilote
Passez limit_req_dry_run à off uniquement après analyse. Rechargez NGINX sans arrêt brutal et surveillez immédiatement taux de 429, latence et erreurs backend. Les clients doivent appliquer un backoff raisonnable ; un retry instantané en boucle peut aggraver la saturation.
nginx -t
nginx -s reload
- Le pilote limite réellement les excès sans hausse anormale d’erreurs métier.
Tester des scénarios contrôlés
Depuis un environnement de test, envoyez une cadence normale puis une rafale au-dessus du seuil. Vérifiez les codes HTTP et les logs. Testez aussi deux clients distincts afin de confirmer que la clé sépare bien leurs quotas. N’utilisez pas un test de charge massif contre la production.
for i in $(seq 1 40); do curl -s -o /dev/null -w '%{http_code}n' https://api.example.tld/api/v1/health; done
- La cadence normale passe et la rafale produit les rejets attendus.
Étendre par endpoint et superviser
Déployez progressivement vers les autres routes. Les endpoints d’authentification, recherche lourde, export ou upload peuvent avoir des limites différentes. Ajoutez un dashboard 429, latence, backend 5xx et top clients limités. Révisez les seuils après changement d’usage ou montée en charge.
- La limitation devient une politique observable et ajustable, pas une règle oubliée.
Validation
La procédure est validée lorsque :
- Le seuil est basé sur des métriques et la clé de quota correspond à l’identité réelle du client.
- Le dry-run a été observé avant activation et les clients légitimes critiques ont été testés.
- Les rafales au-delà du seuil reçoivent le code attendu sans indisponibilité du backend.
- Les métriques permettent de distinguer trafic normal, limitation et erreur applicative.
Retour arrière
- Réactiver limit_req_dry_run on pour neutraliser les rejets tout en conservant les mesures.
- Commenter ou retirer la directive limit_req de l’endpoint puis valider nginx -t avant reload.
- Restaurer la configuration versionnée précédente si plusieurs zones ou clés ont été modifiées.
- Conserver les logs des 429 afin d’ajuster le seuil après rollback.
Dépannage / erreurs fréquentes
- Tous les utilisateurs sont limités ensemble : la clé utilise probablement l’IP du reverse proxy au lieu du client réel.
- 429 sur un client batch légitime : créer une politique dédiée ou corriger sa cadence plutôt que supprimer toute protection.
- Pas de logs de limitation : vérifier que la location réellement utilisée hérite de la directive attendue.
- 503 au lieu de 429 : définir limit_req_status ou vérifier la configuration chargée.
- La zone se remplit : dimensionner la mémoire et revoir la cardinalité de la clé.