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
- Unified external ingress for a microservice cluster; auth and rate limit at the gateway
- Malicious API calls, credential stuffing, or high-frequency scraping; need rate limiting
- Intercept SQL injection, XSS, and other web attacks at ingress with a unified WAF policy
- Replace static Nginx config with declarative routing and security rules across services
Prerequisites
- Docker 20.10+ or bare-metal install (this guide uses Docker Compose)
- 2GB+ RAM recommended (APISIX and etcd)
- Firewall: open 9080 (HTTP ingress) and 9180 (Admin API; internal-only recommended)
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
- No auth key → 401; correct key → 200
- Loop requests to trip the limiter; requests beyond rate+burst → 429
- Blacklisted IP → 403; reverse-check allow-list logic
- SQL injection payload blocked by modsecurity → 403; normal requests unaffected
- `docker compose ps` containers healthy; Admin API changes take effect on `curl http://127.0.0.1:9080/anything` with no restart
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.