Adaptive API Rate Limiting in Nginx with Redis — custom implementation
By Kevin Marcondes · Published on · 7 min read
Adaptive rate limiting for Nginx APIs with Redis backing. The goal is to curb abuse without blocking legitimate clients by adjusting limits per route, plan, bursts, error rates and recent usage. The solution works across multiple Nginx instances and keeps counters consistent in Redis.
What is adaptive rate limiting in Nginx with Redis
Adaptive rate limiting applies limits that change based on client behavior and API state. In Nginx this is implemented with decision logic (Lua via OpenResty or njs) that queries and updates counters in Redis.
With Redis, limits remain consistent across multiple Nginx nodes. Keys can be scoped by API key, IP, route, OAuth scope or tenant, and the server returns 429 responses with headers such as X-RateLimit-Remaining and Retry-After.
Who should consider this service
This service suits REST or GraphQL APIs that suffer bursts, aggressive scraping, unpredictable third-party integrations, or need fairness across plans.
It also helps protect sensitive endpoints like login, checkout and webhooks. As part of API security, a rate limiter complements strong authentication and mTLS. If you need mTLS between Nginx and services, see this practical Docker Compose guide: mTLS with smallstep.
How the implementation works in practice
The implementation pairs Nginx as a reverse proxy with Redis as the counters store. Nginx calls decision logic (Lua on OpenResty or njs) to increment keys, read windows and decide whether to allow, delay or block.
Keys use TTLs to define windows. For consistency and performance, Redis operations are atomic via scripts, with pipelining and persistent connections. Response headers expose remaining limits and reset time to the client.
Which adaptive policies we can apply
Policies are tailored by route, plan and risk. You can tune bucket refill, penalize bursts and increase tolerance for stable clients. Combining IP and credential limits reduces false positives.
Practical examples include looser limits for cacheable reads, stricter limits for login endpoints, and different weights per endpoint. For admin panels and rate limiter guidance, see: admin panel security & rate limiting.
- Token bucket with dynamic refill based on plan and overall service health.
- Sliding window with gradual penalties for continued bursts.
- Progressive temporary bans for high rates of 401/403/5xx responses.
- Endpoint weights (e.g. /search costs 1, /report costs 5).
- Partial allowlists for trusted webhooks with audit logging and expiration.
| Strategy | How it works | When to use | Redis cost |
|---|---|---|---|
| Token bucket | Credits accumulate at a refill rate; each call consumes credits. | Elastic traffic with short bursts. | Low: 1 key per subject. |
| Sliding window | Counts events in a moving window using multiple TTLs. | Fine control for continuous bursts. | Medium: 2–3 keys per subject. |
| Fixed window | Counters reset every fixed period. | Simplicity and predictability. | Low: 1 key per period. |
| Leaky bucket | Queue with constant drain; can enqueue or delay requests. | Smooth out peaks without immediate blocking. | Medium: 1–2 keys + some state. |
Project step-by-step
The workflow goes from diagnosis to a controlled rollout. Each phase focuses on minimizing accidental blocks and tuning policies to real traffic.
When appropriate, rollout can be canaryed with metrics and automated rollback. See an example canary strategy with Nginx here: canary deploy.
- 1) Discovery: critical routes, identification keys, plans and SLAs.
- 2) Policy design and Redis key format (TTLs, prefixes).
- 3) PoC in staging with sampling and shadow mode (measure-only).
- 4) Load and abuse testing: bursts, invalid credentials, top keys.
- 5) Canary rollout and fine-tuning of limits/headers.
- 6) Documentation, runbooks and handover to the team.
Signs you need this now
These symptoms commonly indicate the need for adaptive limiting. They often appear alongside reports of latency and instability during peaks.
- Spikes in 5xx responses during campaigns or external integrations.
- Worker queues saturated by clients with unbalanced usage.
- Login/brute-force spikes despite CAPTCHA or 2FA.
- High scraping activity on public search endpoints.
- Repeated webhooks causing duplicate processing.
What you get at the end
You receive a rate limiter aligned with your product risk profile, with clear operational procedures and client-facing signals via headers. The solution is reproducible and auditable.
For continuous visibility, integrate metrics into your existing stack. If you use Prometheus and Grafana, this guide helps with the basics: Prometheus + Grafana.
- Policies implemented in Nginx with Redis, versioned scripts and keys.
- Standardized limit headers and 429 error pages/JSON.
- Runbooks: how to tune limits and respond to incidents.
- Decision logs and metrics by route, subject and block reason.
- Fallback plan: fail-open/closed options, short timeouts and local caches.
Latency and availability impact
Impact depends on Redis latency and policy choices. On a local network with pipelining and keepalive, overhead is low. For distant regions, prefer replicas close to the Nginx nodes.
For availability, define failure behavior per route: fail-open for low-risk public routes and fail-closed for critical operations. Short decision caches and circuit breakers prevent cascading failures. For volumetric attacks, combine with network mitigation: mitigate DDoS.
Adaptive rate limiting in Nginx with Redis lets you calibrate risk without degrading user experience. The right design avoids bottlenecks and keeps behavior predictable.
Frequently asked questions
What's the difference between Nginx's limit_req and using Redis?
limit_req uses Nginx's shared memory, which works well for a single node. With Redis, counters are centralized and consistent across multiple instances, enabling adaptive policies, endpoint weights and progressive bans without unbalancing the cluster.
Do I need OpenResty for this to work?
Not necessarily. OpenResty (Lua) provides high flexibility. In many cases, njs (JavaScript in Nginx) with Redis is sufficient. The choice depends on atomicity requirements, policy complexity and available modules in your environment.
What happens if Redis becomes unavailable?
You can choose fail-open or fail-closed behavior per route. Short timeouts, local decision caches and emergency keys in Nginx memory reduce impact. The strategy is defined according to your risk tolerance: maximize availability or enforce strict protection.
Can I apply different limits per customer plan?
Yes. Redis keys can include the plan, and refill rates or maximum bucket sizes vary by plan. You can also assign endpoint weights and limited exemptions to trusted webhooks with audit trails and expirations.
Does this stop DDoS attacks?
It helps mitigate application-layer abuse. For volumetric attacks you need network-level protection and upstream filtering. Combine with L3/L4 filters and, where applicable, eBPF/XDP techniques—see the linked DDoS mitigation guide for complements.
Which metrics should I monitor after enabling the limiter?
Track 429 rates by route and subject, Redis latency and errors, decision time, top keys, percentage of bursts penalized and impacted conversions. These metrics guide fine-tuning and prevent accidental blocks during peaks.
Ready to implement your adaptive rate limiter?
Get an initial diagnostic of critical routes, traffic patterns and risks, plus a tailored policy design for Nginx with Redis.
Request diagnosticSee also
- DNS diagnosis and remediation service for name resolution between Docker containers and the host (bridge, overlay, systemd-resolved)
- Proactive PostgreSQL connection and pool monitoring with alerts to prevent 'too many connections' during billing peaks
- Linux Server PCI‑DSS Preparation Service (hardening, logging, network segmentation)
- Service: Implementing a Deploy Pipeline with Automatic Rollback and Smoke Tests for PHP Apps