# Configure Rate Limiting

Rate limiting allows you to restrict the number of requests a client can make to your APIs within a specific time window. This protects your backend services from being overwhelmed by too many requests and ensures fair usage among all users.

API7 Enterprise provides two plugins for rate limiting:

* [`limit-count`](https://docs.api7.ai/hub/limit-count.md): A simple rate limiting plugin that counts requests within a fixed time window.
* [`limit-count-advanced`](https://docs.api7.ai/hub/limit-count-advanced.md): An advanced version that supports sliding windows, multiple rules, and Redis Sentinel.

The scenarios below reuse one service and route. Verify each scenario before applying the next one because a later scenario updates the route's plugin configuration and becomes the only active rate limiter.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

* An API7 Enterprise instance is running.
* A Gateway Group is created and a Gateway instance is running.
* A [token from the Dashboard](https://docs.api7.ai/api7-gateway/reference/obtain-dashboard-token.md).

## Configure Basic Rate Limiting[​](#configure-basic-rate-limiting "Direct link to Configure Basic Rate Limiting")

The [`limit-count`](https://docs.api7.ai/hub/limit-count.md) plugin is ideal for simple rate limiting scenarios, such as limiting each IP address to 5 requests per minute.

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/services/rate-limit-service?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "rate-limit-service",

    "upstream": {

      "type": "roundrobin",

      "scheme": "http",

      "nodes": [

        {

          "host": "httpbin.org",

          "port": 80,

          "weight": 100

        }

      ]

    }

  }'



curl -k "https://localhost:7443/apisix/admin/routes/rate-limit-route?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "rate-limit-route",

    "methods": ["GET"],

    "paths": ["/get"],

    "service_id": "rate-limit-service",

    "plugins": {

      "limit-count": {

        "count": 5,

        "time_window": 60,

        "rejected_code": 429,

        "rejected_msg": "Too Many Requests",

        "key": "remote_addr",

        "policy": "local"

      }

    }

  }'
```

adc.yaml

```
services:

  - name: rate-limit-service

    upstream:

      nodes:

        - host: httpbin.org

          port: 80

          weight: 1

    routes:

      - name: rate-limit-route

        uris:

          - /get

        methods:

          - GET

        plugins:

          limit-count:

            count: 5

            time_window: 60

            rejected_code: 429

            rejected_msg: "Too Many Requests"

            key_type: var

            key: remote_addr

            policy: local

    labels:

      docs-example: rate-limit-service
```

Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:

```
adc diff -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=rate-limit-service
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=rate-limit-service
```

Send six GET requests. The first five requests should succeed and the sixth should return `429`:

```
for i in {1..6}; do

  curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1:9080/get"

done
```

## Configure Distributed Rate Limiting[​](#configure-distributed-rate-limiting "Direct link to Configure Distributed Rate Limiting")

In a multi-node Gateway deployment, use the `redis` policy to share the rate limit counters across all nodes.

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/services/rate-limit-service?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "rate-limit-service",

    "upstream": {

      "type": "roundrobin",

      "scheme": "http",

      "nodes": [

        {

          "host": "httpbin.org",

          "port": 80,

          "weight": 100

        }

      ]

    }

  }'



curl -k "https://localhost:7443/apisix/admin/routes/rate-limit-route?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "rate-limit-route",

    "methods": ["GET"],

    "paths": ["/get"],

    "service_id": "rate-limit-service",

    "plugins": {

      "limit-count": {

        "count": 5,

        "time_window": 60,

        "rejected_code": 429,

        "policy": "redis",

        "redis_host": "127.0.0.1",

        "redis_port": 6379,

        "redis_password": "your-password",

        "redis_database": 0,

        "allow_degradation": true

      }

    }

  }'
```

adc.yaml

```
services:

  - name: rate-limit-service

    upstream:

      nodes:

        - host: httpbin.org

          port: 80

          weight: 1

    routes:

      - name: rate-limit-route

        uris:

          - /get

        methods:

          - GET

        plugins:

          limit-count:

            count: 5

            time_window: 60

            rejected_code: 429

            policy: redis

            redis_host: "127.0.0.1"

            redis_port: 6379

            redis_password: "your-password"

            redis_database: 0

            allow_degradation: true

    labels:

      docs-example: rate-limit-service
```

Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:

```
adc diff -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=rate-limit-service
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=rate-limit-service
```

Set `allow_degradation` to `true` to allow traffic even if the Redis server is unreachable.

After confirming that Redis is reachable, send six GET requests. The first five requests should succeed and the sixth should return `429`:

```
for i in {1..6}; do

  curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1:9080/get"

done
```

## Configure Advanced Rate Limiting[​](#configure-advanced-rate-limiting "Direct link to Configure Advanced Rate Limiting")

The [`limit-count-advanced`](https://docs.api7.ai/hub/limit-count-advanced.md) plugin supports a **sliding window** algorithm, which prevents traffic bursts that can occur at the boundary of fixed windows. It also allows defining multiple rules in a single plugin instance.

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/services/rate-limit-service?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "rate-limit-service",

    "upstream": {

      "type": "roundrobin",

      "scheme": "http",

      "nodes": [

        {

          "host": "httpbin.org",

          "port": 80,

          "weight": 100

        }

      ]

    }

  }'



curl -k "https://localhost:7443/apisix/admin/routes/rate-limit-route?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "rate-limit-route",

    "methods": ["GET"],

    "paths": ["/get"],

    "service_id": "rate-limit-service",

    "plugins": {

      "limit-count-advanced": {

        "window_type": "sliding",

        "policy": "local",

        "rejected_code": 429,

        "rules": [

          {

            "count": 3,

            "time_window": 60,

            "key": "$remote_addr"

          },

          {

            "count": 1000,

            "time_window": 3600,

            "key": "$http_x_api_key"

          }

        ]

      }

    }

  }'
```

adc.yaml

```
services:

  - name: rate-limit-service

    upstream:

      nodes:

        - host: httpbin.org

          port: 80

          weight: 1

    routes:

      - name: rate-limit-route

        uris:

          - /get

        methods:

          - GET

        plugins:

          limit-count-advanced:

            window_type: sliding

            policy: local

            rejected_code: 429

            rules:

              - count: 3

                time_window: 60

                key: "$remote_addr"

              - count: 1000

                time_window: 3600

                key: "$http_x_api_key"

    labels:

      docs-example: rate-limit-service
```

Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:

```
adc diff -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=rate-limit-service
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=rate-limit-service
```

In this example, each client IP is limited to 3 requests per minute, and each API key is limited to 1,000 requests per hour.

Send four GET requests. The first three requests should succeed and the fourth should return `429`:

```
for i in {1..4}; do

  curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1:9080/get" \

    -H "X-API-Key: demo-client"

done
```

## Interpret Rate-Limit Responses[​](#interpret-rate-limit-responses "Direct link to Interpret Rate-Limit Responses")

The rejected request uses the configured `429 Too Many Requests` response.

If the route returns `404` immediately after you apply the configuration, wait a few seconds for the latest configuration to reach the gateway and retry.

The basic and distributed scenarios include `X-RateLimit` headers if `show_limit_quota_header` is enabled (default is `true`):

```
HTTP/1.1 429 Too Many Requests

X-RateLimit-Limit: 5

X-RateLimit-Remaining: 0

X-RateLimit-Reset: 45
```

An admitted advanced request that reaches both rules can include one quota-header set for each. Without a configured `header_prefix`, the rule index is used, such as `X-1-RateLimit-Limit` for the first rule and `X-2-RateLimit-Limit` for the second. If the first rule rejects a request, evaluation stops before the second rule, so the rejection response can include only the first rule's header set.

## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting")

* **Redis Connection Issues**: Ensure the Gateway nodes have network access to the Redis server and that the credentials are correct. Check the Gateway logs for connection errors.
* **Wrong `limit-count` key type**: For `limit-count`, set `key_type` to `var` when `key` names a request variable such as `remote_addr`, or to `constant` when `key` is a literal value.
* **Invalid `limit-count-advanced` rule key**: A rule has no `key_type`. Its `key` is a variable expression, so prefix variables with `$`, such as `$remote_addr`. A value without a variable reference is skipped; if every rule is skipped, the gateway returns HTTP `500` by default.
* **Latency with Redis**: If Redis latency is affecting request performance, consider using the `local` policy for high-frequency low-latency limits, or tune the `sync_interval` for redis-based policies.

## Next Steps[​](#next-steps "Direct link to Next Steps")

* [Implement Traffic Splitting](https://docs.api7.ai/api7-gateway/how-to-guides/traffic-management/canary-release.md) — route a percentage of traffic to new versions.
* [Configure Proxy Rewrite](https://docs.api7.ai/api7-gateway/how-to-guides/traffic-management/proxy-rewrite.md) — modify request URIs and headers before proxying.
