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 Keycloak)
key-authAPI key authentication
basic-authHTTP Basic authentication
openid-connectOpenID Connect (Keycloak 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