Docs

Startup Configuration Reference

Reference for AISIX gateway startup configuration formats, resource sources, connection settings, loading precedence, and common options.

This reference documents the startup configuration file that defines process-level settings such as listeners, resource-source connectivity, TLS, observability, cache and rate-limit backends, and the AISIX Enterprise connection.

Models, caller API keys, provider keys, guardrails, cache policies, and observability exporters are not defined in the startup configuration. For an open-source AISIX gateway, a resources.yaml file or etcd supplies them. For a gateway connected to AISIX Enterprise, the control plane supplies them.

AISIX accepts YAML, TOML, or JSON startup configuration files. Common files include:

  • config.yaml: the local startup configuration file loaded by AISIX.
  • config.example.yaml: a complete store-backed example for a gateway that runs without a control plane. You can copy or mount it as the loaded config.yaml.
  • config.managed.yaml: the gateway bootstrap configuration used when AISIX Enterprise supplies resources at runtime.

The examples below use YAML because the packaged example configurations use YAML. TOML and JSON files can define the same startup fields. For the task-oriented setup flow, see Startup Configuration.

Configuration Models

Every AISIX gateway uses a startup configuration file. The management model determines where its dynamic resources come from and which settings the operator owns directly.

Gateway configurationResource sourceSelect withHow changes arrive
Open-source AISIX gateway using a resources fileDeclarative fileresources_fileLoaded at startup and reloaded on SIGHUP.
Open-source AISIX gateway using a configuration storeAn etcd cluster you manageetcdInitial synchronization followed by etcd watch events.
AISIX gateway connected to AISIX EnterpriseAISIX Enterprise control planemanaged.enabled: true and the generated connection settingsThe gateway receives resources projected by the control plane through its managed etcd connection.

The proxy, downstream, upstream, cache, rate-limit backend, and local observability settings remain gateway startup settings in every model. AISIX Enterprise supplies dynamic resources such as models, keys, policies, and exporters; it does not replace these process-level settings.

For an open-source AISIX gateway, admin.enabled defaults to true, but the default admin.addr value of 127.0.0.1:0 selects an ephemeral port rather than a stable address for operators. To expose the read-only Admin API, set admin.addr to a private or loopback address with a fixed port and configure at least one admin.admin_keys value. Set admin.enabled to false to disable the listener. Configure resources through a resources file or by writing them directly to etcd. A gateway connected to AISIX Enterprise never binds the gateway Admin API.

Common Startup Configuration

The following example shows an open-source AISIX gateway that uses etcd, with common startup settings. The gateway can instead load dynamic resources from a resources_file; see Resource Source.

config.yaml.tmpl
etcd:
  endpoints:                          # etcd endpoints used to store dynamic gateway resources.
    - "http://127.0.0.1:2379"
  prefix: "/aisix"                    # Key prefix used by AISIX in etcd.
  # env_id: "ENVIRONMENT_ID"          # Optional environment scope for gateway resources in etcd.
  # user: "aisix"                     # Optional etcd username.
  # password_env: "AISIX_ETCD_PASSWORD" # Environment variable containing the etcd password.
  # dial_timeout_ms: 5000             # Optional bound on the whole dial to etcd — TCP connect, TLS
                                      # handshake, and authentication. Unset and 0 both apply no timeout.
  # request_timeout_ms: 5000          # Optional bound on a single request-response etcd call, including
                                      # the configuration read. Unset and 0 both apply no timeout. See
                                      # "etcd Configuration Store" before setting it.
  # tls:                              # mTLS settings; all three certificate fields are required together.
  #   ca_cert_file: "/etc/aisix/mtls/ca.crt"
  #   client_cert_file: "/etc/aisix/mtls/client.crt"
  #   client_key_file: "/etc/aisix/mtls/client.key"
  #   domain_name: "${ETCD_HOST}" # Optional SNI and certificate-name override.

proxy:
  addr: "0.0.0.0:3000"                # Address for caller-facing proxy APIs.
  # request_body_limit_bytes: 0       # Maximum request body size. 0, the default, applies no cap.
                                      # Set a byte value to bound per-request memory. See
                                      # "Limit Request Body Size" below for rejection behavior.
  # thread_per_core: true             # Serve from independent workers, each with its own listener
                                      # and upstream connection pool. Omitted, it is on for Linux
                                      # and off elsewhere. Set false to serve from one shared
                                      # runtime. Applied at startup; restart to change.
                                      # See Deployment > Thread-per-Core Workers.
  # workers: 4                        # Number of proxy worker threads, in either serving mode.
                                      # Omitted, it follows the parallelism available to the
                                      # process, so a container CPU limit or a taskset affinity
                                      # mask sizes it. Must be at least 1. Applied at startup.
  # tls:                              # HTTPS certificate and key for the single listener addr describes.
  #   cert_file: "/etc/aisix/tls/proxy.crt"
  #   key_file: "/etc/aisix/tls/proxy.key"
  # listeners:                        # Several proxy listeners, each with its own optional TLS — for a
                                      # deployment that answers HTTPS and plaintext HTTP at the same time.
                                      # Set, this is the COMPLETE set of proxy listeners: only these
                                      # addresses are bound, addr above is ignored (it stays required, and
                                      # the gateway logs one line at startup saying so), and tls above must
                                      # be absent. Every listener serves the same routes and configuration.
                                      # See Deployment > TLS and mTLS for the rules and the env-var form.
  #   - addr: "0.0.0.0:3443"
  #     tls:
  #       cert_file: "/etc/aisix/tls/proxy.crt"
  #       key_file: "/etc/aisix/tls/proxy.key"
  #   - addr: "0.0.0.0:3000"
  # real_ip:                          # Caller IP resolution when AISIX runs behind trusted proxies.
  #   trusted_proxies:
  #     - "10.0.0.0/8"
  #   recursive: true
  #   header: "x-forwarded-for"
  # url_rewrites:                     # Entry-level path rewriting before routing (first match wins).
  #   - name: per-server-mcp-compat   # Optional label used in gateway logs.
  #     match: "^/mcp-servers/([^/]+)/mcp$"  # Regex on the raw request path.
  #     rewrite: "/mcp/$1"            # Replaces the matched portion; broken rules fail startup.
  #                                   # See Deployment > URL Rewriting for full semantics.

admin:
  enabled: false

observability:
  service_name: "aisix"               # Service name used in telemetry.
  log_level: "info"                   # Process log level.
  metrics:
    prometheus:
      enabled: true                   # Whether to expose Prometheus metrics.
      path: "/metrics"                # Metrics endpoint path.
      addr: "0.0.0.0:9090"            # Dedicated metrics/status listener address.

# managed:                            # Enable when this gateway uses the AISIX Enterprise control plane.
#   enabled: true

# cache:                              # Redis connection used by cache policies that select Redis.
#   redis:
#     mode: "single"
#     url: "redis://127.0.0.1:6379"
#     # nodes: ["redis://10.0.0.1:6379"]        # Cluster mode seed nodes.
#     # sentinels: ["redis://10.0.0.1:26379"]   # Sentinel mode nodes.
#     # master_name: "mymaster"                  # Sentinel mode master group.
#     # username: "default"                      # Cluster or Sentinel data-node ACL user.
#     # password: "replace-me"                   # Cluster or Sentinel data-node ACL password.
#     # database: 0                              # Sentinel master database index.
#     # timeout_secs: 5                          # Bounds one Redis round-trip and one connection attempt. Minimum 1.
#     # For single mode, put credentials in the Redis URL.

ratelimit:
  backend: "memory"                   # Rate-limit counter backend. Use redis for shared counters across replicas.
  # redis:
  #   mode: "single"
  #   url: "redis://127.0.0.1:6379"
  #   # nodes: ["redis://10.0.0.1:6379"]        # Cluster mode seed nodes.
  #   # sentinels: ["redis://10.0.0.1:26379"]   # Sentinel mode nodes.
  #   # master_name: "mymaster"                  # Sentinel mode master group.
  #   # username: "default"                      # Cluster or Sentinel data-node ACL user.
  #   # password: "replace-me"                   # Cluster or Sentinel data-node ACL password.
  #   # database: 0                              # Sentinel master database index.
  #   # timeout_secs: 5                          # Bounds one Redis round-trip and one connection attempt. Minimum 1.
  #   # For single mode, put credentials in the Redis URL.
  # concurrency_ttl_secs: 300          # Redis backend only. Reclaims stale concurrency slots.

upstream:                             # Outbound calls to providers. Values shown are the defaults.
  pool_idle_timeout_secs: 30          # Keep below the shortest idle timeout between the gateway and the provider.
  # timeout_ms: 6000000               # Default request deadline (6000 s) when neither the model nor its group/router sets `timeout`. 0 disables the backstop.
  # stream_timeout_ms: 0              # Default streaming chunk-gap deadline. 0 falls back to `timeout_ms`.
  # retries: 2                        # Attempts after a retryable failure, when neither the model nor its group/router sets `retries`. 0 disables retrying.
  # connect_timeout_ms: 5000          # Budget for DNS, TCP, and TLS. On /v1/realtime it also
                                      # covers the WebSocket upgrade handshake. 0 disables.
  # tcp_keepalive_secs: 60            # Idle time before the first keepalive probe. 0 disables.
  # tcp_keepalive_interval_secs: 30   # Interval between keepalive probes.
  # tcp_keepalive_retries: 5          # Unacknowledged probes before the connection is dropped.
  # pool_max_idle_per_host: 32        # Cap on idle connections per upstream host. Unset means
                                      # unbounded. Applies per worker to worker-local pools.
  # tls:                              # Which certificates the gateway trusts when it calls out.
  #   ca_file: "/etc/aisix/tls/private-ca.pem"    # Trusted in addition to the platform's own authorities.
  #   client_cert_file: "/etc/aisix/tls/client.crt"  # For supported HTTP upstreams that require mutual TLS.
  #   client_key_file: "/etc/aisix/tls/client.key"   # Required together with client_cert_file.
  #   verify: true                    # false disables verification where supported. Test environments only.

downstream:                           # Connection layer for inbound calls from clients. Values shown are the defaults.
  idle_timeout_secs: 0                # Close a connection idle between requests. 0 never closes.
  # sse_keepalive_interval_secs: 15   # Heartbeat interval on a silent streaming response. 0 disables.

# Optional deployment-wide override for AWS Bedrock guardrail traffic.
# bedrock_endpoint_url: "https://bedrock-runtime.us-east-1.amazonaws.com"

This is a template when ETCD_HOST is enabled. Render only that value with envsubst '${ETCD_HOST}' < config.yaml.tmpl > config.yaml; the restricted variable list preserves other runtime $ expressions.

Changes to the startup configuration take effect after restarting the gateway.

Limit Request Body Size

proxy.request_body_limit_bytes defaults to 0, which applies no gateway-side cap. Providers accept larger requests than any single fixed default would allow, so setting a limit can reject a request the selected provider would otherwise serve. Earlier AISIX releases defaulted to 10485760 bytes (10 MiB).

Set a byte value when the gateway accepts requests directly from untrusted clients and must bound per-request memory. Alternatively, enforce a body limit at the load balancer or ingress in front of the gateway.

AISIX rejects an over-limit request with 413 Content Too Large, but the caller is not guaranteed to receive that response. For a request that declares an over-limit Content-Length, AISIX first drains the body so it can return the 413 on the same connection. That drain is bounded by bytes and time. If the caller does not finish sending within those bounds, the gateway stops reading and the caller usually sees a closed or reset connection instead. A chunked body is rejected while the handler reads it and does not use the same drain path.

On the Content-Length path, the aisix::body_limit log entry and aisix_proxy_request_body_limit_rejections_total distinguish a completed drain from a cap, timeout, or client read error. See Metrics and Logs for the fields and correlation workflow.

Tune the Upstream Connection Layer

The upstream block controls how the gateway opens and reuses connections to providers. The defaults suit a gateway that reaches providers directly over the internet. Tune them when the gateway sits behind a load balancer, NAT gateway, corporate proxy, or service mesh.

pool_idle_timeout_secs is the setting to review first. The gateway reuses pooled connections, so this value must stay below the shortest idle timeout anywhere on the path to the provider. If an intermediate hop closes an idle connection sooner than the gateway expires it, the pool eventually hands out a connection the far end has already closed, and the request fails with a transport error against an otherwise healthy provider.

TCP keepalive keeps the connection visible to those same hops while a slow model produces its first token. A NAT or load-balancer idle timer can otherwise reap a connection that is legitimately waiting on a long-running request.

In thread-per-core serving, the default on Linux, normal proxy dispatches use worker-local connection pools, and pool_max_idle_per_host applies per worker. The idle connections a process holds toward one host can therefore reach proxy.workers times this cap. Request paths with dedicated clients, such as Provider Keys with custom TLS settings, keep separate process-wide pools and are not included in that multiplication. See Thread-per-Core Workers for the serving modes and their sizing consequences.

timeout_ms and stream_timeout_ms are deployment-wide defaults for the per-model timeout and stream_timeout fields. A request resolves its deadline from the first level that sets one: the target model, then the routing model or semantic router it was addressed through, then these defaults. The default of 6000 seconds is a backstop, not a responsiveness target — it exists so that an upstream that accepted the connection and then goes silent forever cannot hold a request open indefinitely, while never cutting a legitimate long request (deep-reasoning calls can run past ten minutes; set a per-model timeout to enforce anything tighter). A model opts out of the backstop with timeout: 0; setting timeout_ms: 0 removes the default deployment-wide.

Zero-value behavior is field-specific. upstream.timeout_ms: 0 removes the deployment-wide request deadline, and timeout: 0 on a model stops that request-timeout fallback chain. In contrast, upstream.stream_timeout_ms: 0 falls back to upstream.timeout_ms, while stream_timeout: 0 on a model defers to the remaining stream-timeout and request-timeout chain. A zero stream-timeout value can therefore leave an effective streaming deadline in place.

upstream.tls supplies deployment-wide TLS settings for outbound connections. ca_file applies to HTTP request paths, the Realtime WebSocket, Amazon Bedrock, and object-store exports. The client-certificate and verification settings have narrower transport support.

Set ca_file when a private or enterprise certificate authority signed the certificate an upstream presents. Those certificates are trusted in addition to the platform's, so public providers stay reachable. See TLS and mTLS for the support matrix, per-endpoint trust, mutual TLS, and the settings for a Redis backend.

Tune the Downstream Connection Layer

The downstream block is the mirror of upstream: it controls the connections the gateway accepts from clients, or from a gateway placed in front of it.

idle_timeout_secs closes a connection that sits idle between requests — the response has been fully written and no next request has started. A request in flight is never interrupted, however long the model takes, and neither is a streaming response. The same deadline also bounds how long a freshly accepted connection may take to send its first request line and headers, so keep it comfortably above the round-trip time of the slowest client you serve.

It defaults to 0, which never closes an idle connection and leaves that decision to the peer. That default is deliberate. Whatever sits in front of the gateway pools its own connections, and the node that closes first is the one that hands its peer a connection the peer still considers usable — the same failure pool_idle_timeout_secs avoids in the outbound direction. If you set idle_timeout_secs, keep it above the pool idle timeout of the node in front, and treat reclaiming idle connections as the reason to set it.

sse_keepalive_interval_secs emits an SSE comment on a streaming response while the model has produced nothing. Without it, a model that is slow to its first token looks like an abandoned connection to a proxy between the client and the gateway. The comment is ignored by every conforming SSE client, and applies to every streaming endpoint.

Both settings apply to the proxy listener. idle_timeout_secs applies to HTTP/1.1 connections.

How the Timeouts Relate

Each setting below bounds a different phase of a request. They are not interchangeable.

SettingWhereWhat it bounds
upstream.connect_timeout_msStartup configDNS, TCP, and TLS to the provider, before a request is sent. On /v1/realtime, the HTTP 101 upgrade handshake as well.
upstream.timeout_msStartup configDefault for timeout when neither the model nor the routing model / semantic router it was addressed through sets one.
upstream.stream_timeout_msStartup configDefault for stream_timeout; 0 falls back to upstream.timeout_ms.
upstream.pool_idle_timeout_secsStartup configHow long an unused connection to the provider stays in the pool, after a response completes.
downstream.idle_timeout_secsStartup configHow long an accepted client connection stays open with no request on it.
timeoutModelThe whole upstream call, from send to the last byte. Resolves model → routing model / semantic router → upstream.timeout_ms; 0 on the model disables it.
stream_timeoutModelThe gap between two chunks of a streaming response — the wait for the first chunk and every gap after it, reset on each chunk. Not a cap on total stream duration. 0 or absent falls back to the group/router stream_timeout, then to timeout, then to the deployment defaults.

The two pool settings manage connection reuse; the model settings bound a request that is in flight. TCP keepalive is a network-layer liveness probe and bounds nothing at the request layer.

Readers coming from a general-purpose proxy usually look for a connect / send (write) / read timeout trio. The mapping: connect_timeout_ms is the connect timeout; stream_timeout is the read timeout for streaming responses (same inter-chunk semantics), while non-streaming responses get the stricter end-to-end timeout instead; there is no separate send timeout because a stalled request upload is already bounded by the same end-to-end or streaming budget, and unacknowledged sends are cut earlier still at the TCP layer. A general-purpose proxy needs the trio because it has no per-request deadline concept — the gateway does, so the trio is covered with fewer knobs.

For a chain of gateways, the rule at every hop is the same: a node's client-side idle timeout must stay below the next node's server-side idle timeout, with margin. A violation of that ordering is what produces intermittent transport errors against an otherwise healthy path.

Resource Source

Configure exactly one resource source. The selection affects how resources are loaded, but does not change the caller-facing Proxy API.

Resources File

An open-source AISIX gateway reads its dynamic resources from exactly one source. Set resources_file to load them from a declarative resources file:

config.yaml
resources_file: /etc/aisix/resources.yaml

resources_file and the etcd section are mutually exclusive — configuring both fails at startup. resources_file also cannot be combined with managed.enabled: true, because a gateway connected to AISIX Enterprise receives resources from the control plane.

With resources_file set, the gateway loads the file at startup and reloads it on SIGHUP. See the Resources File Reference for every resource kind and field. Use the Open-Source AISIX Gateway Quickstart for the workflow and the CLI Reference for validation or etcd export. Configuration Status shows what a running gateway loaded.

etcd Configuration Store

Set etcd.endpoints when configuration automation writes resources directly to etcd:

config.yaml.tmpl
etcd:
  endpoints:
    - "https://${ETCD_HOST}:2379"
  prefix: "/aisix"
  tls:
    ca_cert_file: "/etc/aisix/mtls/ca.crt"
    client_cert_file: "/etc/aisix/mtls/client.crt"
    client_key_file: "/etc/aisix/mtls/client.key"
    domain_name: "${ETCD_HOST}"

Set ETCD_HOST, then render the startup configuration. envsubst is provided by GNU gettext:

read -rp "etcd host: " ETCD_HOST && export ETCD_HOST
envsubst '${ETCD_HOST}' < config.yaml.tmpl > config.yaml

To recover the last accepted configuration across a process restart, enable the on-disk snapshot cache and follow Restart from Cached Configuration. Configuring a cache path alone does not enable recovery.

FieldRequiredDescription
etcd.endpointsYesOne or more etcd endpoints. An open-source AISIX gateway requires this field when resources_file is not set.
etcd.prefixNoKey prefix containing AISIX resources. Defaults to /aisix; gateways sharing resources must use the same prefix.
etcd.env_idNoEnvironment scope included in the key layout when the writer uses environment-scoped keys.
etcd.userNoetcd username.
etcd.password_envNoName of the environment variable that contains the etcd password.
etcd.dial_timeout_msNoOptional bound on the whole dial to an etcd endpoint, in milliseconds: the TCP connect, the TLS handshake above it, and the authentication exchange performed when etcd.user is set. Unset by default; unset and 0 both apply no timeout.
etcd.request_timeout_msNoOptional bound on a single request-response etcd call, in milliseconds. Unset by default; unset and 0 both apply no timeout. Read the note below before setting it.
etcd.tlsNoClient CA, certificate, key, and optional server-name override for an mTLS connection. The three certificate-file fields are required together.

Both etcd timeouts are optional and unset by default. Leaving a key out applies no timeout to what it covers, and setting it to 0 means exactly the same thing. 0 reads as unbounded here rather than as "fall back to a wider setting" because these two keys are flat, single-level startup settings with no enclosing level to defer to — unlike a model's stream_timeout, whose 0 defers to the next level of a resolution chain.

dial_timeout_ms bounds the whole dial rather than the TCP connect alone: the TLS handshake layered above the connector and the authentication exchange the client performs when etcd.user is set are inside it too. request_timeout_ms bounds a single request-response call: the full-prefix configuration read the gateway issues at boot and on every reconnect, the handshake that creates the configuration watch, and the admin API's own reads — and each dial one of those calls has to make for itself, when the connection it needs is not already established.

Creating the watch and consuming it are bounded differently, on purpose. Creating one is a request-response exchange — the gateway sends the create request and waits for etcd to confirm it — so request_timeout_ms covers it when the key is set. The long-lived stream that comes back is never bounded by it, because any such bound would expire during an interval quiet enough to produce no event and leave the gateway reconnecting instead of watching. Bounding the create closes a failure that is otherwise invisible: an etcd that answers the configuration read but never confirms the watch leaves the gateway serving its first snapshot indefinitely, blind to every later change, while /status/config still reports the source connected.

The established watch stream above is the one exchange neither key bounds, and that is deliberate. Everything else the gateway does against etcd sits under one of the two, the connect-time authentication included: dial_timeout_ms covers it at boot, and request_timeout_ms covers it when a later call has to dial for itself.

A dial that runs out of time counts as an etcd that could not be reached, not as one that refused the gateway, so an expired dial_timeout_ms joins the retry path instead of ending the boot. Which etcd failures a boot waits out and which one ends it is described in Startup and the First Configuration.

Leave request_timeout_ms unset unless you specifically want a slow etcd to fail fast. The configuration read grows with the size of the resource set, so a bound the read cannot finish inside aborts it on every attempt and the gateway retries the identical read indefinitely. On a self-hosted etcd gateway, which keeps no snapshot cache unless managed.snapshot_cache_enabled is true, that means the proxy listener never binds at all. Where a snapshot cache is in use, the instance binds on the restored snapshot instead and then serves it unchanged for as long as the bound keeps aborting the read, so its traffic looks healthy while its configuration quietly stops tracking the store. See Startup and the First Configuration.

That makes request_timeout_ms more than a startup knob. The full-prefix read it bounds runs again on every watch reconnect, at which point the proxy listener is already bound, so a value that is too small fails in two different ways. On a gateway with no snapshot cache the proxy port never opens at startup, which is hard to miss. Afterwards nothing in the traffic path changes — the gateway keeps serving the configuration it already applied, and no request fails — while every reconnect read aborts and the applied configuration falls further behind the store. The gateway log is what names the key, in a warning carrying range read exceeded etcd.request_timeout_ms. On /status/config, source.connected turns false and last_failure.last_error_kind reads fetch, but state stays synced, because that field tracks what was applied rather than how current it is. The counter to alert on is aisix_config_reload_failures_total{reason="fetch"} on the metrics listener. Unless a specific need calls for it, leave the key unset.

When etcd.user is set, the gateway authenticates once while connecting and then carries the token that exchange returned for the life of that connection. etcd can stop accepting that token while the credentials behind it stay perfectly valid. The deployment-facing cause is an auth-store revision change: on a cluster issuing JWT tokens, any auth-store edit made by anyone — adding a user, granting a role, changing a permission — invalidates every token issued before it, this gateway's included. A token that reaches the end of its --auth-token-ttl arrives at the same state.

The gateway recovers from that by itself. When etcd answers a call by refusing the token that connection is carrying — usually reported as invalid auth token, and including the two answers revision of auth store is old and user name is empty, which are recognized as meaning the same thing — the gateway discards the connection, dials a new one, which authenticates again, and retries the call once. Before this it kept the refused token until the process was restarted, and read no configuration in the meantime. A credential etcd has actually refused (authentication failed, invalid user ID or password) is deliberately not on that list and still fails on the first answer; no amount of retrying turns a wrong password into a right one. A token still refused on the freshly authenticated connection is reported as a refused token rather than a refused credential, so the two do not get diagnosed as the same thing.

This costs a healthy connection nothing, but it changes the worst case for anyone who sets request_timeout_ms. An attempt bounds its dial and its call separately, and the retry gets a fresh window rather than what was left of the first, so a configuration read that goes through the recovery path can take up to four times the configured value. Both timeout keys are unset by default, so a default deployment is unaffected; size a tight value with that multiple in mind.

Use aisix export when migrating an existing store to a resources file.

AISIX Enterprise

Set managed.enabled to true when the gateway receives resources from AISIX Enterprise. Use the generated gateway installation snippet rather than composing the bootstrap values manually; it supplies the correct control-plane endpoints and certificate material for the selected environment.

config.yaml.tmpl
managed:
  enabled: true
  cp_base_url: "${AISIX_URL}"
  cp_etcd_endpoint: "${AISIX_HOST}:443"
  mtls_dir: "/var/lib/aisix/mtls"
  dp_id_file: "/var/lib/aisix/dp_id"
  snapshot_cache_enabled: false
  snapshot_cache_path: "/var/lib/aisix/config_cache.json"
  heartbeat_interval_secs: 15

Set the origin and host from the generated gateway installation snippet, then render only these two values:

read -rp "AISIX control-plane origin: " AISIX_URL && export AISIX_URL
read -rp "AISIX control-plane host: " AISIX_HOST && export AISIX_HOST
envsubst '${AISIX_URL} ${AISIX_HOST}' < config.yaml.tmpl > config.yaml

The connection certificate, private key, and CA can be supplied as one complete inline triplet (cp_cert_pem, cp_key_pem, and cp_ca_pem) or one complete file-path triplet (cp_cert_file, cp_key_file, and cp_ca_file). Do not mix inline and file forms within the same bundle. Keep credential material in environment variables or mounted secret files rather than committing it to the startup configuration.

FieldRequiredDescription
managed.enabledYesEnables the AISIX Enterprise connection and disables the gateway Admin API listener.
managed.cp_base_urlYesAISIX Enterprise control-plane origin used for heartbeat, telemetry, and budget checks.
managed.cp_etcd_endpointNoExplicit managed etcd endpoint as host:port. When omitted, AISIX derives it from cp_base_url.
managed.cp_ca_cert_fileNoAdditional CA bundle for the control-plane HTTP and etcd TLS connections, commonly needed with a private CA for an On-Premises control plane.
managed.mtls_dirNoDirectory where AISIX persists the materialized mTLS bundle. Defaults to /var/lib/aisix/mtls.
managed.dp_id_fileNoFile where AISIX persists the gateway ID. Defaults to /var/lib/aisix/dp_id.
managed.snapshot_cache_enabledNoEnable on-disk configuration recovery across restarts. Defaults to false in both managed and self-hosted etcd modes. Running gateways retain accepted configuration in memory regardless of this setting.
managed.snapshot_cache_pathNoCache file location when persistence is enabled. Omitted or null uses /var/lib/aisix/config_cache.json; an empty string disables persistence. A path alone does not enable the cache.
managed.heartbeat_interval_secsNoHeartbeat interval in seconds. Defaults to 15 and is clamped to the range 5–300.

The managed connection appears as source.type: "etcd" in Configuration Status, because the gateway consumes the control plane's projected resources through its managed store connection. For the certificate issuance and installation workflow, see Connect an AISIX Gateway. For environment-variable forms of these fields, see Environment Variables.

Select a Configuration File

When running the binary directly, provide a config path with --config.

aisix --config config.yaml

When running the official container image, mount the config file at /etc/aisix/config.yaml, or set AISIX_CONFIG_PATH to another path inside the container.

The following example mounts a production config file and asks the entrypoint to load it:

docker run \
  -v "$(pwd)/config.prod.yaml:/etc/aisix/config.prod.yaml:ro" \
  -e AISIX_CONFIG_PATH="/etc/aisix/config.prod.yaml" \
  ghcr.io/api7/aisix:dev

If AISIX_CONFIG_PATH is unset, the entrypoint uses /etc/aisix/config.yaml.

Loading Order

AISIX loads startup configuration in the following order:

  1. Built-in default values.
  2. File contents from the path selected by --config.
  3. Environment-variable overrides with the AISIX_ prefix.

Environment-variable overrides apply only to startup configuration fields. For override syntax and AISIX Enterprise connection variables, see Environment Variables.