limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/s; server { location /api/ { limit_req zone=general burst=20 nodelay; } location /api/auth/login { limit_req zone=auth burst=3 nodelay; }
}
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/s; server { location /api/ { limit_req zone=general burst=20 nodelay; } location /api/auth/login { limit_req zone=auth burst=3 nodelay; }
}
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/s; server { location /api/ { limit_req zone=general burst=20 nodelay; } location /api/auth/login { limit_req zone=auth burst=3 nodelay; }
}
import redis
from datetime import datetime, timedelta r = redis.Redis() def is_rate_limited(user_id, limit=100, window_seconds=3600): key = f"rate_limit:{user_id}:{int(datetime.now().timestamp() // window_seconds)}" current = r.incr(key) r.expire(key, window_seconds) return current > limit @app.route('/api/resource')
def get_resource(): if is_rate_limited(current_user.id): return {'error': 'Rate limit exceeded'}, 429 return process_request()
import redis
from datetime import datetime, timedelta r = redis.Redis() def is_rate_limited(user_id, limit=100, window_seconds=3600): key = f"rate_limit:{user_id}:{int(datetime.now().timestamp() // window_seconds)}" current = r.incr(key) r.expire(key, window_seconds) return current > limit @app.route('/api/resource')
def get_resource(): if is_rate_limited(current_user.id): return {'error': 'Rate limit exceeded'}, 429 return process_request()
import redis
from datetime import datetime, timedelta r = redis.Redis() def is_rate_limited(user_id, limit=100, window_seconds=3600): key = f"rate_limit:{user_id}:{int(datetime.now().timestamp() // window_seconds)}" current = r.incr(key) r.expire(key, window_seconds) return current > limit @app.route('/api/resource')
def get_resource(): if is_rate_limited(current_user.id): return {'error': 'Rate limit exceeded'}, 429 return process_request()
response.headers['X-RateLimit-Limit'] = '100'
response.headers['X-RateLimit-Remaining'] = '87'
response.headers['X-RateLimit-Reset'] = unix_timestamp
response.headers['X-RateLimit-Limit'] = '100'
response.headers['X-RateLimit-Remaining'] = '87'
response.headers['X-RateLimit-Reset'] = unix_timestamp
response.headers['X-RateLimit-Limit'] = '100'
response.headers['X-RateLimit-Remaining'] = '87'
response.headers['X-RateLimit-Reset'] = unix_timestamp - Public endpoints (search, info): 100 req/min per IP
- Auth endpoints (login, signup): 5 req/min per IP + distributed rate limit
- Resource creation (write APIs): 10 req/min per user
- Admin endpoints: 1000 req/day per user (tight control) - [ ] Deploy Nginx rate limiting (zone + limit_req directive)
- [ ] Set up Redis account (free tier)
- [ ] Write rate limit middleware in your framework
- [ ] Define endpoint-specific limits
- [ ] Add rate limit headers to responses
- [ ] Test with Apache Bench or Vegeta load testing tool
- [ ] Set up alerts (Slack notification when a user hits limits)
- [ ] Document rate limits in your API docs - Only IP-based limiting: Punishes corporate networks and VPNs.
- No graduated response: Ban immediately instead of throttling first.
- Storing counts in database: Too slow. Use Redis or in-memory cache.
- Not exposing rate limit headers: Clients can't intelligently back off.
- Ignoring health check endpoints: Don't rate limit your own monitoring. - Check Redis keys: redis-cli KEYS "rate_limit:*"
- Inspect their request pattern: high burst vs sustained?
- Whitelist their IP/user if it's a legitimate use case
- Adjust thresholds based on real traffic patterns - Ready-to-deploy Nginx configs for all major frameworks
- Redis setup guide (AWS ElastiCache, DigitalOcean, Heroku)
- Complete Python/Node.js middleware code
- GitHub Actions workflow for load testing
- Real abuse patterns from production SaaS systems
- Cost optimization strategies (cache tiers, fallback limits)
- Comprehensive debugging guide
- Whitelist/bypass strategies for trusted partners