API7 Docs

limit-count plugin for API7 Gateway

Skill for configuring the API7 Enterprise Edition (API7 EE) limit-count plugin via the a7 CLI. Covers fixed-window rate limiting, count/time_window conf…

Overview

The limit-count plugin rate-limits requests using a fixed-window counter algorithm. Define a maximum number of requests (count) within a time interval (time_window). Supports per-IP, per-consumer, per-header, or custom variable keys. For distributed API7 EE deployments, use Redis or Redis-cluster as the shared counter backend.

When to Use

  • Simple request counting (e.g., 100 requests per hour)
  • API quota enforcement per consumer or API key
  • Shared rate limits across multiple API7 EE nodes (via Redis)
  • Grouped quotas across multiple routes

Plugin Configuration Reference

Core Fields

FieldTypeRequiredDefaultDescription
countintegerYes*Max requests allowed in the time window. > 0
time_windowintegerYes*Time window in seconds. > 0
key_typestringNo"var"Key type: "var", "var_combination", or "constant"
keystringNo"remote_addr"Variable name or combination for counting
rejected_codeintegerNo503HTTP status on rejection (200–599)
rejected_msgstringNoCustom rejection message body
groupstringNoShare counters across routes with same group ID
policystringNo"local"Storage: "local", "redis", or "redis-cluster"
show_limit_quota_headerbooleanNotrueInclude X-RateLimit-* headers in responses
allow_degradationbooleanNofalseAllow requests when plugin fails

*Required unless using rules array.

Redis Fields (when policy: "redis")

FieldTypeRequiredDefaultDescription
redis_hoststringYesRedis server address
redis_portintegerNo6379Redis port
redis_usernamestringNoRedis ACL username
redis_passwordstringNoRedis password
redis_databaseintegerNo0Redis database index
redis_timeoutintegerNo1000Timeout in milliseconds
redis_sslbooleanNofalseEnable TLS to Redis

Redis Cluster Fields (when policy: "redis-cluster")

FieldTypeRequiredDefaultDescription
redis_cluster_nodesarray[string]YesArray of "host:port" (min 2)
redis_cluster_namestringYesCluster name
redis_passwordstringNoCluster password
redis_timeoutintegerNo1000Timeout in milliseconds
redis_cluster_sslbooleanNofalseEnable TLS

Key Types

key_typekey FormatExampleDescription
"var"NGINX variable (no $)"remote_addr"Single variable
"var_combination"$var1 $var2"$remote_addr $consumer_name"Multiple variables combined
"constant"Any string"global"Same counter for all requests

Response Headers

When show_limit_quota_header: true (default):

HeaderDescription
X-RateLimit-LimitTotal quota for the time window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetSeconds until counter resets

Step-by-Step: Basic Rate Limiting

1. Rate limit by client IP (route-level)

a7 route create -g default -f - <<'EOF'
{
  "id": "rate-limited-api",
  "uri": "/api/*",
  "plugins": {
    "limit-count": {
      "count": 100,
      "time_window": 60,
      "key_type": "var",
      "key": "remote_addr",
      "rejected_code": 429,
      "rejected_msg": "Rate limit exceeded. Try again later."
    }
  },
  "upstream": {
    "type": "roundrobin",
    "nodes": [{"host": "backend", "port": 8080, "weight": 1}]
  }
}
EOF

100 requests per 60 seconds per client IP.

2. Rate limit per consumer

a7 consumer create -g default -f - <<'EOF'
{
  "username": "free-tier",
  "plugins": {
    "limit-count": {
      "count": 100,
      "time_window": 3600,
      "rejected_code": 429
    }
  }
}
EOF

a7 consumer create -g default -f - <<'EOF'
{
  "username": "premium",
  "plugins": {
    "limit-count": {
      "count": 10000,
      "time_window": 3600,
      "rejected_code": 429
    }
  }
}
EOF

Consumer-level limits apply across all routes the consumer accesses.

Common Patterns

Shared quota across routes (group)

{
  "plugins": {
    "limit-count": {
      "count": 1000,
      "time_window": 3600,
      "group": "api-v1",
      "rejected_code": 429
    }
  }
}

All routes with "group": "api-v1" share the same 1000 req/hour counter. Important: All routes in a group must have identical limit-count config.

Multi-variable key (IP + consumer)

{
  "plugins": {
    "limit-count": {
      "count": 50,
      "time_window": 60,
      "key_type": "var_combination",
      "key": "$remote_addr $consumer_name",
      "rejected_code": 429
    }
  }
}

Global rate limit (all requests share one counter)

{
  "plugins": {
    "limit-count": {
      "count": 10000,
      "time_window": 60,
      "key_type": "constant",
      "key": "global",
      "rejected_code": 429
    }
  }
}

Distributed rate limiting with Redis

{
  "plugins": {
    "limit-count": {
      "count": 1000,
      "time_window": 60,
      "key": "remote_addr",
      "policy": "redis",
      "redis_host": "redis.example.com",
      "redis_port": 6379,
      "redis_password": "secret",
      "redis_database": 0,
      "redis_ssl": true,
      "rejected_code": 429
    }
  }
}

Use Redis when running multiple API7 EE nodes to share counters.

Redis cluster

{
  "plugins": {
    "limit-count": {
      "count": 1000,
      "time_window": 60,
      "key": "remote_addr",
      "policy": "redis-cluster",
      "redis_cluster_nodes": [
        "192.168.1.10:6379",
        "192.168.1.11:6379",
        "192.168.1.12:6379"
      ],
      "redis_cluster_name": "apisix-cluster",
      "redis_password": "secret",
      "rejected_code": 429
    }
  }
}

Troubleshooting

SymptomCauseFix
Limits not shared across API7 EE nodesUsing policy: "local" (default)Switch to "redis" or "redis-cluster"
Group config rejectedMismatched configs in same groupEnsure all routes in group have identical limit-count config
Unexpected counter resetFixed-window boundaryNormal behavior — counters reset at fixed intervals
Key empty, all clients share one counterVariable doesn't existVerify key variable name; falls back to remote_addr
Rate limit headers missingshow_limit_quota_header: falseSet to true (default)
503 instead of 429Default rejected_code is 503Set rejected_code: 429 explicitly

Fixed-Window Algorithm Note

limit-count uses a fixed-window algorithm. Counters reset at exact intervals. This means a burst at the boundary of two windows can temporarily exceed the intended rate (e.g., 100 req/min allows 200 requests if 100 come at t=59s and 100 at t=61s). For smoother rate limiting, combine with limit-req (leaky bucket).

Config Sync Example

version: "1"
gateway_groups:
  - name: default
    consumers:
      - username: free-tier
        plugins:
          limit-count:
            count: 100
            time_window: 3600
            rejected_code: 429
    routes:
      - id: rate-limited-api
        uri: /api/*
        plugins:
          limit-count:
            count: 1000
            time_window: 60
            key: remote_addr
            rejected_code: 429
        upstream:
          type: roundrobin
          nodes:
            - host: backend
              port: 8080
              weight: 1

This page is generated from a7-plugin-limit-count/SKILL.md in the api7/a7 repository. Browse all skills on the AI Agent Skills page.