> ## Documentation Index
> Fetch the complete documentation index at: https://qovery-docs-rde-install-script.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Setup Rate Limit on Services

> Configure rate limiting for services using NGINX

This guide covers implementing rate limits on Qovery services through NGINX customization. Rate limiting helps protect services from abuse. While third-party solutions like Cloudflare are recommended for filtering traffic before it reaches workloads, this tutorial demonstrates cluster-level implementation.

<Warning>
  Changing NGINX snippets configuration is an advanced feature and can lead to misconfiguration. Please be careful when changing these settings as it might break the whole NGINX configuration.
</Warning>

## Prerequisites

* Application running on a Qovery managed cluster
* Basic understanding of NGINX rate limiting

## Understanding NGINX Rate Limiting

NGINX rate limiting protects your services by controlling the rate of requests. For detailed information, see [NGINX's official documentation on rate limiting](https://www.nginx.com/blog/rate-limiting-nginx/).

***

## Initial Setup

### Configure Test Service

We'll use `jmalloc/echo-server` Docker image for testing:

* Image: `jmalloc/echo-server`
* Port: 80

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/service-initial-setup-qovery-screen.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=afa7a606eaff7213877de6e05cf0d9b0" alt="Service initial setup" width="1211" height="315" data-path="images/nginx-rate-limit/service-initial-setup-qovery-screen.png" />
</Frame>

### Configure NGINX Replicas

Rate limits apply per NGINX instance. For demonstration, set replicas to 1 (not recommended for production):

1. Go to **Cluster Settings** → **Advanced Settings**
2. Find `nginx.controller.replicas`
3. Set value to `1`

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/cluster-advanced-settings-replicas.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=c7a32178307cb5c1775446912d54f8f4" alt="Set NGINX replicas" width="814" height="102" data-path="images/nginx-rate-limit/cluster-advanced-settings-replicas.png" />
</Frame>

<Info>
  Without rate limits: 100 req/sec × 500 requests = 100% success rate (all HTTP 200 responses)
</Info>

***

## Global Rate Limit Implementation

### Declare at Cluster Level

Configure `nginx.controller.http_snippet`:

```nginx theme={null}
limit_req_zone "$server_name" zone=global:10m rate=10r/s;
```

**Components:**

* `$server_name`: Rate limit key (can use `$http_x_forwarded_for` for IP-based limits)
* `zone=global:10m`: Zone name with 10MB memory allocation
* `rate=10r/s`: 10 requests per second threshold

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/cluster-advanced-settings-set-global-rate-in-http-snippet.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=592ebe4783bb6004094df7079a4d3557" alt="Set global rate in http snippet" width="1245" height="691" data-path="images/nginx-rate-limit/cluster-advanced-settings-set-global-rate-in-http-snippet.png" />
</Frame>

### Apply Rate Limit

Configure `nginx.controller.server_snippet`:

```nginx theme={null}
location / {
    limit_req zone=global;
}
```

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/cluster-advanced-settings-set-global-rate-in-server-snippet.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=ed8abb33c88e1e27d509c1901ebb1dcb" alt="Apply global rate in server snippet" width="1272" height="663" data-path="images/nginx-rate-limit/cluster-advanced-settings-set-global-rate-in-server-snippet.png" />
</Frame>

### Deploy Changes

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/deploy-cluster-after-advanced-settings-changes.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=1cf52d89fdbcb74bbbd95cbc5bd09981" alt="Deploy cluster changes" width="1272" height="551" data-path="images/nginx-rate-limit/deploy-cluster-after-advanced-settings-changes.png" />
</Frame>

### Enhancement with Burst

Adding `burst=20 nodelay;` permits 20-request bursts without delays:

```nginx theme={null}
location / {
    limit_req zone=global burst=20 nodelay;
}
```

### Test Results

Load test: 100 req/sec for 500 total requests

**Result:**

* 452 HTTP 503 rejections
* 48 HTTP 200 acceptances (\~9.6 req/sec)

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/nginx-logs-rejecting-requests-with-global-rate.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=329818a841fd3dd02a2631ed65fd3171" alt="Global rate limit logs" width="1268" height="627" data-path="images/nginx-rate-limit/nginx-logs-rejecting-requests-with-global-rate.png" />
</Frame>

***

## Service-Level Rate Limit

Configure rate limiting at the service level using advanced settings:

**Configuration Settings:**

* `network.ingress.nginx_limit_rps`: Rate in requests/second
* `network.ingress.nginx_limit_rpm`: Rate in requests/minute
* `network.ingress.nginx_limit_burst_multiplier`: Burst multiplier (default: 5)

### Example: 10 Requests/Minute with 2× Burst

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/service-advanced-settings-set-limit-rpm-and-burst.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=a8304d09adacb2cb137f3c53d372c607" alt="Service-level rate limit" width="1277" height="661" data-path="images/nginx-rate-limit/service-advanced-settings-set-limit-rpm-and-burst.png" />
</Frame>

<Info>
  When both RPM and RPS are set, both rate limits will be enforced simultaneously. Traffic will be restricted based on whichever limit is hit first.
</Info>

### Deploy Service

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/deploy-service.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=d9c4b0016e245e2d7ae0bc5a6b3fbb25" alt="Deploy service with rate limit" width="1275" height="643" data-path="images/nginx-rate-limit/deploy-service.png" />
</Frame>

### Test Results

* 479 HTTP 503 rejections
* 21 HTTP 200 acceptances

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/nginx-logs-rejecting-requests-with-service-rate.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=90a8377ae608a96984e375d733b59981" alt="Service rate limit logs" width="1272" height="694" data-path="images/nginx-rate-limit/nginx-logs-rejecting-requests-with-service-rate.png" />
</Frame>

***

## Custom Header-Based Rate Limiting

Implement rate limiting based on custom HTTP headers.

### Cluster Configuration

Configure `nginx.controller.http_snippet`:

```nginx theme={null}
map $http_x_qovery_api_key $limit_key {
    default $http_x_qovery_api_key;
    "" "anonymous";
}

limit_req_zone $limit_key zone=qovery_api_limit:10m rate=5r/s;
```

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/cluster-advanced-settings-set-custom-header-rate-in-http-snippet.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=2a231c9960253da5c56fb3f3080000c5" alt="Custom header rate limit declaration" width="3410" height="1320" data-path="images/nginx-rate-limit/cluster-advanced-settings-set-custom-header-rate-in-http-snippet.png" />
</Frame>

**Details:** Maps HTTP header values to rate limit keys; missing headers default to "anonymous" designation.

### Service Configuration

Configure `network.ingress.nginx_controller_configuration_snippet`:

```nginx theme={null}
limit_req zone=qovery_api_limit burst=2 nodelay;
```

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/service-advanced-settings-set-customer-header-rate-limiter-in-configuration-snippet.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=5d94d58739fdd81008889ab112a713c7" alt="Apply custom header rate limit" width="3410" height="946" data-path="images/nginx-rate-limit/service-advanced-settings-set-customer-header-rate-limiter-in-configuration-snippet.png" />
</Frame>

**Burst Parameter Explanation:**

* `burst=2`: Permits 2 extra requests beyond rate limit during short bursts
* `nodelay`: Disables request queuing; excess requests rejected immediately

### Deploy and Test

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/deploy-service-with-custom-header-rate-limiter.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=212ac9fc6243c87323243fb0d5a56ec2" alt="Deploy with custom header rate limit" width="3418" height="1302" data-path="images/nginx-rate-limit/deploy-service-with-custom-header-rate-limiter.png" />
</Frame>

**Test Command:**

```bash theme={null}
oha -q 100 -n 500 -H "X-QOVERY-API-KEY: benjamin"
```

**Result:**

* 473 HTTP 503 rejections
* 27 HTTP 200 acceptances (\~5.4 req/sec with burst)

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/nginx-logs-rejecting-requests-with-custom-header-in-service-logs.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=1b7601444805fc92e8765c8c7fb961de" alt="Service logs with custom header" width="1273" height="703" data-path="images/nginx-rate-limit/nginx-logs-rejecting-requests-with-custom-header-in-service-logs.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/nginx-logs-rejecting-requests-with-custom-header.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=54f1179c91722c903ad28a42773bdc09" alt="NGINX logs with custom header" width="1240" height="127" data-path="images/nginx-rate-limit/nginx-logs-rejecting-requests-with-custom-header.png" />
</Frame>

***

## Additional Configuration

### Custom HTTP Status Code

Configure `nginx.controller.limit_request_status_code`:

* Default: HTTP 503
* Alternative: HTTP 429 (commonly used for rate limiting)

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/cluster-advanced-settings-custom-limit-http-status.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=197515812bd9db7f67afa47bc9228473" alt="Custom HTTP status code" width="1276" height="577" data-path="images/nginx-rate-limit/cluster-advanced-settings-custom-limit-http-status.png" />
</Frame>

Test results show HTTP 429 responses:

<Frame>
  <img src="https://mintcdn.com/qovery-docs-rde-install-script/DgfeVZ1u_ufYlivW/images/nginx-rate-limit/cluster-advanced-settings-custom-limit-http-status-logs.png?fit=max&auto=format&n=DgfeVZ1u_ufYlivW&q=85&s=819506c16f2206e456f34e53aeb9655f" alt="HTTP 429 response logs" width="3394" height="608" data-path="images/nginx-rate-limit/cluster-advanced-settings-custom-limit-http-status-logs.png" />
</Frame>

### Connection Limits

Configure `network.ingress.nginx_limit_connections` at service level to limit concurrent connections from single IP addresses.

***

## Summary

<AccordionGroup>
  <Accordion title="Global Rate Limit">
    Applied at cluster level, affects all services. Best for protecting the entire cluster from abuse.
  </Accordion>

  <Accordion title="Service-Level Rate Limit">
    Applied per service using `nginx_limit_rps` or `nginx_limit_rpm`. Best for protecting individual services.
  </Accordion>

  <Accordion title="Header-Based Rate Limit">
    Applied based on custom HTTP headers. Best for API key-based rate limiting and multi-tenant applications.
  </Accordion>

  <Accordion title="Connection Limits">
    Limits concurrent connections per IP. Best for preventing connection exhaustion attacks.
  </Accordion>
</AccordionGroup>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Advanced Settings" icon="sliders" href="/configuration/service-advanced-settings">
    Configure service advanced settings
  </Card>

  <Card title="NGINX Configuration" icon="server" href="/configuration/integrations/api-gateway-nginx">
    Learn about NGINX ingress
  </Card>

  <Card title="Cluster Configuration" icon="layer-group" href="/configuration/clusters">
    Configure cluster settings
  </Card>

  <Card title="Security Best Practices" icon="shield" href="/getting-started/security-and-compliance/overview">
    Implement security measures
  </Card>
</CardGroup>
