DevOps & Linux 3d ago 5 views 5 min read

How to configure Nginx rate limiting for API abuse protection

Stop API abuse by setting up Nginx limit_req zones. Configure the limit_req directive to throttle requests per IP, protect endpoints, and return 429 Too Many Requests when the threshold is exceeded.

Master Sensei
Updated 7h ago
Sponsored

Cloud VPS — scale in minutes

Instantly deploy SSD cloud VPS with guaranteed resources, snapshots and per-hour billing. Pay only for what you use.

Configure Nginx to limit the number of requests an IP address can make within a specific time window. This guide targets Nginx 1.24.0 running on Ubuntu 24.04 or Debian 12. You will define a zone, assign it to a location block, and return a 429 status code when the limit is exceeded.

Prerequisites

  • OS: Ubuntu 24.04, Debian 12, or compatible Linux distribution.
  • Package: Nginx 1.24.0 or later installed via apt or dnf.
  • Module: The ngx_http_limit_req_module must be compiled into Nginx (standard on most distros).
  • Privileges: Root access or sudo to edit configuration files.
  • Network: Access to the Nginx configuration directory, typically /etc/nginx/sites-available or /etc/nginx/nginx.conf.

Step 1: Create a rate limiting zone

Define a shared memory zone that tracks request counts for each IP address. The zone name must be unique and the size must be a multiple of 16KB. A 10MB zone with a 10-second burst capacity allows 10,000 concurrent requests per IP.

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

This command creates a zone named api_limit capable of tracking 10,000 IPs (10MB / 1KB per entry). The rate is set to 10 requests per second. If an IP exceeds this rate, Nginx increments a counter. When the counter exceeds the burst value, Nginx returns a 429 status.

Step 2: Assign the zone to a location block

Apply the zone to the specific API endpoint you want to protect. Use the limit_req directive inside the location block. The first parameter specifies the zone name. The second parameter sets the burst capacity and defines how many excess requests to queue before rejecting them.

location /api/endpoint {
    limit_req zone=api_limit burst=20 nodelay;

    proxy_pass http://backend;
}

The burst=20 parameter allows 20 requests to queue up if they arrive within a short window. The nodelay flag releases queued requests immediately. Without nodelay, Nginx delays the first burst request, which can cause latency spikes for legitimate traffic.

Step 3: Configure the 429 response

Nginx returns a 503 Service Unavailable by default when rate limits are hit. To protect your API, return a 429 Too Many Requests status instead. This informs clients that they have exceeded their rate limit.

location /api/endpoint {
    limit_req zone=api_limit burst=20 nodelay;
    limit_req_status 429;

    proxy_pass http://backend;
}

The limit_req_status 429 directive changes the default 503 response to 429. This is the standard HTTP status for rate limiting and is better understood by API clients and automated tools.

Verify the installation

Test the configuration syntax to ensure no errors exist before reloading Nginx. Run the following command from the root directory:

nginx -t

Expected output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If the test passes, reload Nginx to apply changes without dropping active connections:

nginx -s reload

Expected output:

2024/05/20 10:00:00 [notice] 1234#1234: signal process started

Send a rapid stream of requests to the endpoint using ab or curl. If you send more than 10 requests per second, you should see a 429 response.

for i in {1..30}; do curl -s -o /dev/null -w "%{http_code}\n" http://your-domain/api/endpoint; done

Expected output (after limit is hit):

200
200
...
429
429

Troubleshooting

Error: "limit_req_zone directive is not allowed in location context"

This error occurs if you placed the zone definition inside a location block. Rate limit zones must be defined in the http context, typically in /etc/nginx/nginx.conf or inside an http block in a site configuration file. Move the limit_req_zone line outside any location blocks.

Error: "limit_req zone=api_limit exceeded"

This message appears in the Nginx error log when a request is rejected. Check the error.log to see if the zone is being hit. If the error rate is too high, increase the rate value or the burst capacity. For example, change rate=10r/s to rate=50r/s if your API can handle more load.

Error: "limit_req_status directive is not allowed here"

This happens if you try to set the status code inside a server block without a location block. Ensure the limit_req_status directive is inside the same location block where limit_req is defined. It must be in the same context as the zone assignment.

Issue: Legitimate traffic is blocked

If legitimate users are blocked, the zone size might be too small for the number of IPs, or the rate is too low. Increase the zone size to accommodate more IPs. Use limit_req_zone $binary_remote_addr zone=api_limit:20m rate=100r/s; to allow 20,000 IPs at 100 requests per second. Also, consider using limit_req_log_level warn in the http block to reduce log noise.

http {
    limit_req_log_level warn;
    ...
}

Issue: 429 responses appear for new IPs immediately

This indicates the zone is empty or the burst is zero. Ensure the burst value is greater than zero. If you use nodelay, the burst acts as a queue. If you want to allow a spike of traffic without queuing, set burst=0 and remove nodelay. However, for API abuse protection, a non-zero burst is recommended to handle legitimate traffic spikes.

location /api/endpoint {
    limit_req zone=api_limit burst=20 nodelay;
    limit_req_status 429;
    proxy_pass http://backend;
}

Issue: Rate limiting does not work for mobile networks

Mobile networks often share a single public IP among many users. To protect against abuse from a single ISP, use the $http_x_forwarded_for variable if behind a proxy. If not, consider using $remote_addr combined with a geo-IP module to limit specific regions. Alternatively, implement a WAF like ModSecurity to detect and block abusive patterns before they hit Nginx.

limit_req_zone $http_x_forwarded_for zone=api_limit:10m rate=10r/s;

Issue: Nginx returns 502 Bad Gateway

This error indicates the backend server is unreachable. Ensure the proxy_pass

Sponsored

Powerful Dedicated Servers — Linux & Windows

Bare-metal performance with SSD storage, DDoS protection and 24/7 expert support. Ideal for production workloads, databases and high-traffic sites.

Tags: securityLinuxNginxAPI
0
Was this helpful?

Related tutorials

Comments 0

Login to leave a comment.

No comments yet — be the first to share your thoughts.