429

Fix 429 Rate Limit Errors on Nginx Reverse Proxy

Server & Cloud Intermediate 👁 16 views 📅 Jun 26, 2026

Nginx returns 429 when API calls hit your rate limit. The culprit is almost always the limit_req directive. Here's how to fix it fast.

When You See This Error

You're running a web app or API behind Nginx, and suddenly clients get 429 Too Many Requests. This happens most often during a traffic spike — say you push a new feature and get 5000 requests per second against an API that normally handles 200. Or a bot goes haywire. The error is clear: Nginx is enforcing a rate limit you set.

Root Cause

Nginx uses the limit_req_zone directive to define a shared memory zone for rate tracking. Then limit_req in a location block checks incoming requests against that zone. When the rate exceeds your configured burst and delay, Nginx drops the request with 429. Simple, but easy to misconfigure.

The typical setup looks like this in nginx.conf http block:

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

And in the location block:

limit_req zone=api burst=20 nodelay;

The rate=10r/s means 10 requests per second. burst=20 allows up to 20 extra requests over the rate. nodelay means those burst requests aren't delayed — they're passed immediately until the burst is exhausted. After that, 429s happen.

So the root cause is either the rate is too low for your actual traffic, or the burst is too small. Or you forgot you set it.

Fix: Step by Step

  1. Find the limit_req_zone line. It's in the http block of your main nginx.conf. Usually at the top. If it's not there, check included files in /etc/nginx/conf.d/ or sites-enabled.
  2. Check the rate. Look at the rate= value. Common examples: rate=30r/s for 30 requests per second. If your API normally handles 100 req/s, you've found the issue. Increase it. Start with rate=100r/s.
  3. Check the burst. In the location block where limit_req appears, increase burst=. A good starting point is double your peak traffic per second. If you expect 200 req/s, set burst=400.
  4. Test without nodelay first. Remove nodelay temporarily. This causes excess requests to be queued and delayed, not dropped. It's friendlier to clients. Only add nodelay if you must drop requests immediately.
  5. Reload Nginx. Run nginx -t to test config, then systemctl reload nginx or nginx -s reload.
  6. Verify. Send a burst of requests using curl or a tool like ab (Apache Bench).
    for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" http://your-api.com/endpoint; done | sort | uniq -c
    If you see no 429s, you're done.

What If It Still Fails?

  • You missed a location. Sometimes limit_req is in multiple location blocks. Check every server block and location in your config files.
  • Another service is rate-limiting. Your app, API gateway, or a CDN like Cloudflare can also return 429. Look at response headers. Nginx adds X-RateLimit-Limit and X-RateLimit-Remaining headers if configured. If you don't see those, the 429 might not be from Nginx.
  • Your rate limit is per IP. $binary_remote_addr tracks by client IP. If traffic comes from a single IP (like a load balancer), all requests hit the same limit. Switch to $http_x_forwarded_for or a custom variable if you trust the header.
  • Logs tell the truth. Check Nginx error log: tail -f /var/log/nginx/error.log. Look for lines like limiting requests, excess: 0.800 by zone "api". This tells you which zone is triggering the limit.
  • You're using limit_req in a wrong context. The limit_req_zone must be in the http block. limit_req goes in server or location. If you put limit_req_zone inside a server block, nginx will complain or ignore it.

One last thing: if you're on a shared hosting or a managed service (like AWS ALB), you might not control Nginx. In that case, check with your provider's docs. But if you manage the box, this fix works. I've used it on Ubuntu 20.04 with Nginx 1.18 and CentOS 7 with Nginx 1.20. Same deal.

Was this solution helpful?