Skip to content

APISIX Configuration Reference ​

APISIX configuration lives in layers/api-gateway/config/apisix.yaml. This file is mounted into the APISIX container and controls the core proxy, plugin loading, admin API, etcd connection, and observability.

Core Settings ​

yaml
apisix:
  node_listen: 9080
  enable_admin: true
  enable_websocket: true
  admin_listen:
    port: 9180
  extra_lua_path: "/usr/local/apisix/apisix/plugins/custom/?.lua;/usr/local/apisix/apisix/plugins/custom/?/init.lua;"
SettingValueDescription
node_listen9080Main proxy port. All API traffic enters here.
enable_admintrueEnables the Admin API for route/consumer management.
enable_websockettrueEnables WebSocket proxying.
admin_listen.port9180Admin API port.
extra_lua_path(see above)Adds the custom plugin directory to the Lua module search path.

Deployment ​

Admin API ​

yaml
deployment:
  admin:
    admin_key:
      - name: admin
        key: $\{\{APISIX_ADMIN_KEY\}\}
        role: admin
    allow_admin:
      - 127.0.0.0/24
      - 172.16.0.0/12
      - 192.168.0.0/16
      - 10.0.0.0/8
SettingDescription
admin_keyAdmin API key. Loaded from APISIX_ADMIN_KEY environment variable. Never hardcode.
allow_adminCIDR blocks allowed to access the Admin API. Restricted to private networks.

DANGER

The Admin API key is set via the $\{\{APISIX_ADMIN_KEY\}\} environment variable. Never commit this value. Use the X-API-KEY header for all Admin API requests.

Example Admin API call:

bash
curl http://localhost:9180/apisix/admin/routes \
  -H "X-API-KEY: $APISIX_ADMIN_KEY"

etcd Connection ​

yaml
deployment:
  etcd:
    host:
      - "http://etcd:2379"
    prefix: "/apisix"
    timeout: 30
SettingValueDescription
hosthttp://etcd:2379etcd endpoint for APISIX configuration storage.
prefix/apisixKey prefix in etcd. All APISIX config stored under this path.
timeout30Connection timeout in seconds.

Plugins ​

All enabled plugins are declared in the plugins list. Only plugins listed here can be used in route configurations.

Standard Plugins ​

Rate Limiting ​

PluginDescription
limit-countFixed window counter rate limiting
limit-reqRequest rate limiting (leaky bucket)
limit-connConcurrent connection limiting

Authentication ​

PluginDescription
jwt-authJWT validation (used with Zitadel)
key-authAPI key authentication
basic-authHTTP Basic authentication
openid-connectOpenID Connect (Zitadel integration)

Traffic Management ​

PluginDescription
proxy-rewriteRewrite upstream URI, host, headers
response-rewriteRewrite response headers/body
redirectHTTP redirect
corsCross-Origin Resource Sharing
ip-restrictionIP allowlist/denylist
request-idGenerate unique request ID
real-ipExtract real client IP from proxy headers
api-breakerCircuit breaker for upstream failures
traffic-splitTraffic splitting for canary/A-B deployments

gRPC Support ​

PluginDescription
grpc-transcodeTranscode HTTP/JSON to gRPC
grpc-webgRPC-Web protocol support

Logging ​

PluginDescription
http-loggerSend access logs via HTTP
tcp-loggerSend access logs via TCP
udp-loggerSend access logs via UDP

Observability ​

PluginDescription
prometheusExpose Prometheus metrics
opentelemetryDistributed tracing via OTel

Extension ​

PluginDescription
ext-plugin-pre-reqExternal plugin runner (pre-request)
ext-plugin-post-respExternal plugin runner (post-response)
serverless-pre-functionInline Lua pre-request
serverless-post-functionInline Lua post-response

Custom Plugins ​

tenant-rate-limit ​

Per-tenant sliding window rate limiter backed by Redis. Runs in the access phase at priority 1001 (after auth, before most other plugins).

Source: layers/api-gateway/plugins/tenant-rate-limit/

Schema (from schema.lua):

ParameterTypeDefaultDescription
redis_hoststring"gw-redis"Redis hostname
redis_portinteger6379Redis port
redis_timeoutinteger1000Redis connection timeout (ms)
redis_pool_sizeinteger100Redis connection pool size
default_countinteger100Default request limit per window
time_windowinteger60Time window in seconds
rejected_codeinteger429HTTP status code for rate-limited requests
rejected_msgstring"Rate limit exceeded for tenant"Error message for rate-limited requests
tenant_headerstring"X-Tenant-ID"Header to extract tenant_id from
allow_missing_tenantbooleanfalseIf false, reject requests without tenant_id
missing_tenant_codeinteger401HTTP status code when tenant_id is missing
show_limit_headerbooleantrueInclude X-RateLimit-* headers in response

Redis key patterns used:

  • rl:{tenant_id}:{route_id}:{window} -- sliding window sorted set
  • rl:config:{tenant_id} -- per-tenant limit override

Response headers (when show_limit_header is true):

  • X-RateLimit-Limit -- max requests per window
  • X-RateLimit-Remaining -- remaining requests
  • X-RateLimit-Reset -- Unix timestamp when window resets
  • X-Tenant-ID -- tenant identifier

Behavior:

  • Uses an atomic Redis Lua script for sliding window counting (single round-trip)
  • Checks for per-tenant limit override in rl:config:{tenant_id} before applying default
  • Fails open if Redis is unreachable (requests are allowed through)
  • Caches the Redis script SHA for subsequent calls via EVALSHA

Route configuration example:

bash
curl http://localhost:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: $APISIX_ADMIN_KEY" \
  -X PUT -d '{
    "uri": "/api/*",
    "upstream": {"type": "roundrobin", "nodes": {"ai-gateway:4000": 1}},
    "plugins": {
      "tenant-rate-limit": {
        "default_count": 500,
        "time_window": 60,
        "redis_host": "gw-redis",
        "redis_port": 6379
      }
    }
  }'

clickhouse-logger ​

Batched request log writer to ClickHouse via the HTTP interface. Runs in the log phase at priority 399.

Source: layers/api-gateway/plugins/clickhouse-logger/init.lua

Schema:

ParameterTypeDefaultDescription
clickhouse_urlstring"http://clickhouse:8123"ClickHouse HTTP endpoint
databasestring"gateway"Target database
tablestring"request_log"Target table (the Buffer table)
timeoutinteger5000HTTP request timeout (ms)
batch_max_sizeinteger100Flush buffer when this many entries accumulate
inactive_timeoutinteger5(Schema default; periodic flush runs every 5 seconds)
buffer_durationinteger60(Schema default for buffer duration)
max_retry_countinteger3Max retries on write failure
retry_delayinteger1Delay between retries (seconds)
tenant_headerstring"X-Tenant-ID"Header to extract tenant_id from

Behavior:

  • Buffers log entries per Nginx worker process
  • Flushes when buffer reaches batch_max_size or every 5 seconds (timer)
  • Writes to ClickHouse using INSERT INTO ... FORMAT JSONEachRow
  • Extracts tenant_id from header, rate-limit plugin context, or JWT payload
  • Scrubs Authorization header -- never logs tokens or credentials
  • Log entry fields: timestamp, tenant_id, route_id, method, path, status_code, latency_ms, request_size, response_size, client_ip, user_agent, trace_id

Route configuration example:

bash
curl http://localhost:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: $APISIX_ADMIN_KEY" \
  -X PATCH -d '{
    "plugins": {
      "clickhouse-logger": {
        "clickhouse_url": "http://clickhouse:8123",
        "database": "gateway",
        "table": "request_log",
        "batch_max_size": 200
      }
    }
  }'

Plugin Attributes ​

Plugin attributes configure global behavior for plugins (shared across all routes).

prometheus ​

yaml
plugin_attr:
  prometheus:
    export_uri: /apisix/prometheus/metrics
    export_addr:
      ip: 0.0.0.0
      port: 9091

Exposes Prometheus metrics on a dedicated port (9091) separate from the main proxy port. Scraped by Prometheus at apisix:9091.

opentelemetry ​

yaml
plugin_attr:
  opentelemetry:
    resource:
      service.name: apisix
    collector:
      address: otel-collector:4317
      request_timeout: 3
    trace_id_source: x-request-id
    batch_span_processor:
      max_queue_size: 1024
      batch_timeout: 2
      inactive_timeout: 1
      max_export_batch_size: 16
SettingValueDescription
resource.service.nameapisixService name in traces
collector.addressotel-collector:4317OTel Collector gRPC endpoint
collector.request_timeout3Timeout for sending spans (seconds)
trace_id_sourcex-request-idUse X-Request-ID header as trace ID
batch_span_processor.max_queue_size1024Max queued spans before drop
batch_span_processor.batch_timeout2Max wait before sending a batch (seconds)
batch_span_processor.inactive_timeout1Timeout for inactive batches (seconds)
batch_span_processor.max_export_batch_size16Max spans per export batch

http-logger ​

yaml
plugin_attr:
  http-logger:
    inactive_timeout: 2
    batch_max_size: 1000
    buffer_duration: 60
SettingValueDescription
inactive_timeout2Flush after 2 seconds of inactivity
batch_max_size1000Max entries per batch
buffer_duration60Max buffer duration in seconds

Custom Plugin Directory Structure ​

Custom plugins are loaded from the extra_lua_path directory. Each plugin follows this structure:

layers/api-gateway/plugins/
  tenant-rate-limit/
    handler.lua      # Plugin lifecycle (access phase)
    schema.lua       # JSON schema for config validation
    init.lua         # Alternative entry point (same logic)
  clickhouse-logger/
    init.lua         # Plugin lifecycle (log phase) + schema

:::note Plugins must be listed in the plugins array in apisix.yaml to be loadable. Adding a plugin directory without listing it in the config will not enable it. :::

Enterprise API + AI + Agent Gateway