← News
/PLAYBOOK · 2026-08-21

Apache APISIX Gateway Security in Practice: WAF and Rate-Limit Configuration Guide

Apache APISIX is a cloud-native API gateway. Auth, rate limiting, and WAF sit at the gateway layer. This guide covers deploy, routes, rate limit, auth, IP blacklist, and ModSecurity integration.

API gateway security shifts controls to the ingress in a microservice architecture. Apache APISIX, a cloud-native API gateway, centralizes identity auth, rate limiting, and WAF at the traffic edge so backends do not reimplement them. This guide covers APISIX deploy and security plugins: IP blacklist, key-auth, limit-req, and ModSecurity WAF, with copy-paste commands.

Use Cases

Prerequisites

How It Works

APISIX is built on OpenResty (Nginx + LuaJIT). Core model: Route → plugin chain → Upstream. Request matches a Route, runs bound plugins (Plugin) in order, then forwards to the Upstream. All security is plugins: ip-restriction for IP allow/deny lists, key-auth for API Key checks, limit-req for token-bucket rate limits, modsecurity to run OWASP CRS at the gateway. Plugin config is pushed via Admin API; no gateway restart.

Procedure

1. Docker Compose deploy

cat > docker-compose.yml <<'EOF'
version: "3.8"
services:
  etcd:
    image: bitnami/etcd:3.5
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379
  apisix:
    image: apache/apisix:3.9.0-debian
    ports:
      - "9080:9080"
      - "9180:9180"
    volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    depends_on: [etcd]
EOF
docker compose up -d
curl http://127.0.0.1:9080/apisix/admin/routes -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" | head -c 200

Admin API default key is edd1c9f034335f136f87ad84b625c8f1. Production must change admin_key in config.yaml.

2. Create upstream and route

curl -X PUT http://127.0.0.1:9180/apisix/admin/upstreams/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "type": "roundrobin",
  "nodes": {"httpbin.org:80": 1}
}'
curl -X PUT http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "uri": "/anything",
  "upstream_id": 1
}'
# Verify forwarding
curl http://127.0.0.1:9080/anything

3. Configure limit-req

curl -X PUT http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "uri": "/anything",
  "upstream_id": 1,
  "plugins": {
    "limit-req": {
      "rate": 2,
      "burst": 4,
      "rejected_code": 429,
      "key_type": "var",
      "key": "remote_addr"
    }
  }
}'
# Send 7 consecutive rapid requests; the 7th should return 429
for i in $(seq 1 7); do curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9080/anything; done

rate is requests allowed per second. burst is the burst buffer. Excess returns 429. Per-client-IP limits blunt CC attacks and crawlers.

4. Configure key-auth

# Create a consumer and assign a Key
curl -X PUT http://127.0.0.1:9180/apisix/admin/consumers \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "username": "app1",
  "plugins": {"key-auth": {"key": "secret-app-key-001"}}
}'
# Bind the auth plugin to the route
curl -X PATCH http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "plugins": {"key-auth": {}}
}'
# Without Key returns 401; with Key succeeds
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9080/anything
curl -s -o /dev/null -w "%{http_code}\n" -H "apikey: secret-app-key-001" http://127.0.0.1:9080/anything

5. Configure IP blacklist

curl -X PATCH http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "plugins": {"ip-restriction": {"blacklist": ["1.2.3.4", "10.0.0.0/8"]}}
}'
# Requests from blacklisted IPs return 403

6. Integrate ModSecurity WAF

# Prepare OWASP CRS rules (mount into the container)
mkdir -p ./crs && cd ./crs
git clone --depth 1 https://github.com/coreruleset/coreruleset.git .
cp crs-setup.conf.example crs-setup.conf
# Edit config.yaml to enable the modsecurity plugin and restart
docker compose restart apisix
# Enable the WAF plugin on the route
curl -X PATCH http://127.0.0.1:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
  "plugins": {"modsecurity": {
    "deployment": "advance",
    "modsecurity_config": "/usr/local/apisix/conf/crs-setup.conf"
  }}
}'
# Test SQL injection blocking: should return 403
curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:9080/anything?id=1%27%20OR%20%271%27%3D%271"

Verification

FAQ

FAQ 1: APISIX vs Nginx rate-limit config?

Nginx limit_req lives in static config; rule changes need reload. APISIX plugins push via Admin API, sync to etcd, take effect in seconds. Per-route, per-consumer, per-upstream control. Dashboard for visual config. Fits multi-service, multi-team gateways.

FAQ 2: Does the modsecurity plugin hurt performance?

Yes. Full OWASP CRS regex-matches every request; QPS drops. Enable WAF only on write or login routes; use limit-req on reads. Or hang modsecurity on a separate plugin chain, attached per route.

FAQ 3: Risk of exposing Admin API to the public internet?

Critical. Attacker can delete routes, disable auth, add a malicious upstream, hijack traffic. Listen on internal ports only (do not expose 9180). Rotate admin_key and restrict source IPs. Monitor Admin API calls in access logs.

Summary

APISIX makes API security one config, fleet-wide: key-auth at the identity edge, limit-req against high-frequency abuse, ip-restriction against bad sources, modsecurity against injection. Mount plugins by interface criticality: rate-limit public reads; stack auth + WAF on sensitive writes; keep Admin API strictly internal. That is a workable gateway-layer defense.