API7 Gateway 3.10.3
Several Data Plane shared memory (lua_shared_dict) defaults were raised, so a 3.10.3 gateway reserves about 365 MiB more shared memory at startup than 3.10.2 with the default configuration:
Release Date: 2026-07-14
Upgrade Notes
Upgrade note — higher default gateway memory usage
Several Data Plane shared memory (lua_shared_dict) defaults were raised, so a 3.10.3 gateway reserves about 365 MiB more shared memory at startup than 3.10.2 with the default configuration:
| Shared dictionary | 3.10.2 default | 3.10.3 default |
|---|---|---|
prometheus-metrics (advanced metrics) | 15 MiB | 128 MiB |
kubernetes, nacos, nacos-stream, consul (service discovery) | 20 MiB each | 64 MiB each |
tracing_buffer (SkyWalking) | 10 MiB | 32 MiB |
api-calls-for-portal | 10 MiB | 64 MiB |
These dictionaries are allocated when the gateway starts, whether or not the corresponding feature is in use, so the increase applies to every 3.10.3 gateway. Before upgrading, raise the gateway container's memory requests and limits (in Kubernetes, also review node memory-pressure and eviction thresholds) so the gateway is not OOM-killed. If you do not use a given feature — for example a service discovery type you have not configured — you can lower its dictionary back toward the previous value through the gateway configuration, or through the shared-dict values in the Helm chart.
Upgrade note — built-in user login policy is stricter
Built-in Dashboard users are now temporarily locked out after repeated failed password attempts. The default policy is enabled, bans the user and source IP after 5 consecutive failures, and lasts 15 minutes. Administrators can tune or disable it through the new login failure restriction system setting. New passwords and passwords changed after upgrade must also be at least 12 characters and still satisfy the existing complexity requirements. Existing passwords are not revalidated at sign-in.
If a built-in user enables two-factor authentication, HTTP Basic Auth for that user is rejected because Basic Auth cannot provide a second factor. Use access tokens for programmatic integrations instead; token authentication is sent with the X-API-KEY header and does not require a 2FA verification code.
Upgrade note — forwarded headers are trusted only from trusted addresses
The gateway now uses apisix.trusted_addresses to decide whether client-supplied X-Forwarded-* and RFC 7239 Forwarded headers are trusted. When trusted_addresses is not configured, or when the request comes from an untrusted address, the gateway overwrites X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Port with gateway-observed values and clears the Forwarded header before proxying upstream. If an upstream application depends on the original forwarded protocol, host, or port sent by a trusted load balancer or reverse proxy, configure that proxy's IP or CIDR in trusted_addresses.
Upgrade note — OpenID Connect silent re-authentication is no longer enabled by default
The openid-connect plugin no longer sets refresh_session_interval to 900 seconds by default. Periodic silent re-authentication now happens only when refresh_session_interval is explicitly configured. If your deployment relied on the previous 900-second refresh behavior, set refresh_session_interval: 900 before or during the upgrade.
Upgrade note — SQL Server deployments enable snapshot reads on first startup
For SQL Server-backed deployments, the Control Plane now creates and prepares the database before other components connect, and enables READ_COMMITTED_SNAPSHOT to prevent gateway configuration reads from blocking behind writes. On an existing SQL Server database where this setting is still disabled, the first startup applies the database-level change with ROLLBACK IMMEDIATE; in-flight database transactions and sessions can be disconnected once, after which connection pools reconnect and later starts are no-ops.
Upgrade note — additional plugin secret fields are encrypted at rest
The Control Plane now encrypts additional credential-bearing plugin fields at rest. Because API7 EE upgrades the Control Plane before the Data Plane, during the upgrade window a 3.10.3 Control Plane encrypts these fields while an older 3.10.2 Data Plane cannot decrypt them, which can cause the affected plugins to fail until the Data Plane is also upgraded.
The newly encrypted fields, by plugin, are:
- ai-cache:
semantic.embedding.openai.api_key,semantic.embedding.azure_openai.api_key
If you use any of these plugins with the listed fields, upgrade the Data Plane to 3.10.3 promptly after the Control Plane, and avoid editing those plugins until both sides are on 3.10.3.
Features
Plugins
- AI Cache (opens in Plugin Hub docs)
- Added a semantic (L2) cache layer that matches prompts by embedding similarity through RediSearch, in addition to exact-match caching. Streaming LLM responses can now be cached and replayed instead of being bypassed. New Prometheus metrics report cache hits, misses, bypasses, and embedding latency.
- AI Aliyun Content Moderation (opens in Plugin Hub docs)
- Added
request_check_rolesto choose which request roles are moderated (user,tool, and/orsystem).userandtoolcontent followrequest_check_mode(lastorall, defaultlast), whilesystemcontent is checked on every request when selected. Long content is now split into chunks in linear time and is multi-byte (UTF-8) safe.
- Added
- AI AWS Content Moderation (opens in Plugin Hub docs)
- Request moderation now runs after AI protocol detection and checks the decoded prompt content that the upstream LLM sees, rather than the raw HTTP JSON envelope. Deny responses are returned in a provider-compatible format, with configurable
check_request,deny_code, anddeny_message.
- Request moderation now runs after AI protocol detection and checks the decoded prompt content that the upstream LLM sees, rather than the raw HTTP JSON envelope. Deny responses are returned in a provider-compatible format, with configurable
- IP Restriction (opens in Plugin Hub docs)
- Added a configurable
response_code(either403or404, default403) returned when a request is blocked, so operators can respond with404to avoid revealing whether a resource exists.
- Added a configurable
- File Logger
- The log file
pathcan now be set once in the plugin metadata and shared across routes, instead of being required in every route's plugin configuration. Apathset in the plugin configuration still takes precedence over the metadata value.
- The log file
- Logger plugins
- Added
max_req_body_bytesandmax_resp_body_bytesto the schemas of HTTP Logger (opens in Plugin Hub docs), RocketMQ Logger (opens in Plugin Hub docs), TCP Logger, Tencent Cloud CLS, and UDP Logger, so the request/response body size limits (default 524288 bytes) are validated at configuration time and shown in the Dashboard.
- Added
- Rate-limiting plugins
- Added Redis connection keepalive settings (
redis_keepalive_timeoutandredis_keepalive_pool) for the Redis and Redis Cluster policies in Limit Count (opens in Plugin Hub docs), Limit Count Advanced (opens in Plugin Hub docs), GraphQL Limit Count (opens in Plugin Hub docs), and AI Rate Limiting (opens in Plugin Hub docs), so operators can tune idle timeout and connection pool size.
- Added Redis connection keepalive settings (
Data Plane
- Added
apisix.trusted_addresses, which controls whether the gateway trusts client-suppliedX-Forwarded-*andForwardedheaders based on the resolved client address. - Added
apisix.match_uri_encoded_slash. When enabled, an encoded slash (%2F) stays encoded during route matching so it can be treated as part of a path parameter instead of a path separator. - In standalone YAML mode, environment-variable placeholders are now resolved before YAML parsing. Unquoted placeholders can become native booleans or numbers, while quoted placeholders stay strings, preserving large IDs and token values exactly.
Control Plane
- Added TOTP two-factor authentication for built-in Dashboard users. Users can enroll, enable, disable, and recover 2FA from their account settings, and administrators can reset a user's 2FA state.
- Added login failure restriction for built-in users. Repeated failed logins temporarily lock the user and source IP, emit an audit event, and return a clear lockout message.
- Added the Dashboard UI for two-factor authentication: account setup with QR code and recovery codes, an OTP step during login, and an administrator action to reset a user's 2FA state.
- Updated password forms and generated passwords to use the new 12-character minimum length.
Developer Portal
- Added an option to require two-factor authentication. When 2FA is enabled and
twoFactor.requiredis set, developers must complete 2FA enrollment before they can access protected pages, and the requirement is enforced both at sign-in and at the proxy layer.
Fixes
Plugins
- AI Proxy (opens in Plugin Hub docs) and AI Proxy Multi (opens in Plugin Hub docs)
- Fixed issue: Anthropic Messages requests that contained tool results mixed with other content could be converted into an invalid OpenAI Chat message order, causing OpenAI-compatible upstreams to reject every later request in the session. Tool messages are now emitted immediately after the assistant tool-call message, and adjacent text or media is preserved in a following user message. Several other Anthropic-to-OpenAI conversion details were aligned with LiteLLM-compatible behavior, including tool name sanitization, long tool-name collision handling, adaptive thinking effort, structured-output schema extraction, empty array encoding, and content block shaping.
- Fixed issue: Structured chat content could reach downstream AI plugins as a table and cause request processing errors. Protocol adapters now flatten text content consistently before AI guard and cache plugins consume it.
- AI Lakera Guard (opens in Plugin Hub docs)
- Fixed issue: In streaming responses with
action: alertandfail_open: false, a Lakera API error or timeout could let the streamed response through instead of failing closed. Lakera errors are now handled according tofail_open, so a strict configuration blocks the response.
- Fixed issue: In streaming responses with
- AI AWS Content Moderation (opens in Plugin Hub docs) and AI Aliyun Content Moderation (opens in Plugin Hub docs)
- Fixed issue:
deny_codeaccepted arbitrary numbers. It is now validated as an integer HTTP status code in the200–599range (default200), so an out-of-range value is rejected at configuration time.
- Fixed issue:
- AI Aliyun Content Moderation (opens in Plugin Hub docs)
- Fixed issue: Returning
ngx.OKfrom the body filter could interrupt later body-filter processing. The plugin now returns normally so other filters can continue.
- Fixed issue: Returning
- AI Rate Limiting (opens in Plugin Hub docs)
- Fixed issue: Some configured Redis fields were dropped and replaced with defaults —
redis_username/redis_passwordfor the redis-sentinel policy andredis_keepalive_timeout/redis_keepalive_poolfor the redis and redis-cluster policies. All configured Redis fields are now forwarded.
- Fixed issue: Some configured Redis fields were dropped and replaced with defaults —
- gRPC Transcode (opens in Plugin Hub docs)
- Fixed issue: Empty protobuf
repeatedfields were encoded as{}instead of JSON arrays ([]). Empty repeated fields now appear as arrays, including nested and descriptor-set based messages.
- Fixed issue: Empty protobuf
- Key Auth (opens in Plugin Hub docs) and other consumer authentication plugins
- Fixed issue: If a consumer credential referenced a secret that could not be resolved, the Data Plane could still index the unresolved literal value and authenticate requests with it. Consumer authentication now fails closed when a referenced secret cannot be resolved.
- Secret references
- Fixed issue: Updates or deletions of
/secretsconfiguration did not invalidate the secret LRU cache, so old secret values could continue to be used until cache expiry or indefinitely. Secret references are now re-resolved after secret configuration changes.
- Fixed issue: Updates or deletions of
- Proxy Rewrite (opens in Plugin Hub docs)
- Fixed issue: With
use_real_request_uri_unsafeanduriconfigured together, the request query string was dropped during URI rewriting. The original query string is now preserved and correctly merged when the rewritten URI already contains a query.
- Fixed issue: With
- Loggly
- Fixed issue: Batched Loggly entries from different routes could use the wrong token or tags because the async handler reused the latest route configuration. Each batch processor now keeps its own route configuration.
- Datadog (opens in Plugin Hub docs)
- Fixed issue: Large coalesced DogStatsD datagrams could exceed the common 8192-byte agent buffer and be silently truncated. The plugin now coalesces only when the payload fits, otherwise it falls back to one datagram per metric.
- Zipkin (opens in Plugin Hub docs)
- Fixed issue: Requests explicitly marked as unsampled still built full span tag tables and access-phase child spans. Unsampled requests now skip that extra tracing work while preserving trace propagation.
- OpenTelemetry (opens in Plugin Hub docs)
- Fixed issue: Updating OpenTelemetry plugin metadata at runtime did not rebuild the tracer used for injected core spans, so those spans could keep using stale collector or resource settings until worker recycle. The tracer now refreshes when metadata changes.
- Fixed issue:
additional_attributeswere evaluated before log-phase variables were populated, so attributes that depend on final request state could be missing or stale. They are now evaluated in the log phase. - Fixed issue: With
trace_id_sourceset tox-request-id, anX-Request-Idvalue that is not valid hexadecimal (for example a UUID), or a duplicated header, could returnHTTP 500. The value is now validated and the plugin falls back to a random valid trace ID when it cannot be used. - Fixed issue: The plugin metadata schema accepted non-scalar values for
resourceattributes andcollector.request_headers, which were then silently dropped at runtime. Such values are now rejected at configuration time.
- OpenID Connect (opens in Plugin Hub docs)
- Fixed issue:
refresh_session_intervalincorrectly defaulted to900, enabling silent re-authentication even when users did not configure it. The default is removed (see Upgrade Notes).
- Fixed issue:
- MQTT Proxy (opens in Plugin Hub docs)
- Fixed issue:
protocol_namewas required even though the standard default isMQTT. It is now optional and defaults toMQTT.
- Fixed issue:
- Forward Auth (opens in Plugin Hub docs)
- Fixed issue: When
request_methodwasPOST, the authorization request could forward the client'sTransfer-Encoding,Content-Length, andExpectheaders after the body had already been buffered, producing inconsistent request framing. These client framing headers are no longer copied to the auth service.
- Fixed issue: When
- Authz CASBIN
- Fixed issue: Routes using different Casbin model or policy shapes could trigger
casbin enforce error/invalid request sizeafter switching between them. The bundledlua-casbindependency is updated to include the enforcement fixes.
- Fixed issue: Routes using different Casbin model or policy shapes could trigger
- Request ID (opens in Plugin Hub docs)
- Fixed issue: Configuring
algorithm: range_idwithout the optional range object could returnHTTP 500. The range object now has a default value.
- Fixed issue: Configuring
- Workflow (opens in Plugin Hub docs)
- Fixed issue: Workflow action plugins could run
_meta.pre_functionhooks before workflow skipped or executed the action, changing behavior even for actions that should not run. Workflow now decides whether to run the action before executing those meta hooks.
- Fixed issue: Workflow action plugins could run
- Request Validation (opens in Plugin Hub docs)
- Fixed issue: A form body whose
Content-Typecarried a charset parameter or different casing (for exampleapplication/x-www-form-urlencoded; charset=utf-8) was not recognized as form-urlencoded, so it was parsed as JSON and rejected withHTTP 400. Such content types are now recognized and validated as form bodies.
- Fixed issue: A form body whose
Data Plane
- Fixed issue: Log rotation could leave some log files open after only part of the file set was rotated. The gateway now reopens logs correctly after partial rotation.
- Fixed issue: When the configuration source reported a smaller revision than the gateway had already seen (for example after the Control Plane database was restored to an earlier state), the gateway could keep serving stale configuration until a worker restart. It now forces a full configuration resync when a smaller revision is observed.
- Fixed issue: A plugin attached through a global rule or a consumer (such as
ai-proxy-multi) could fail withHTTP 5xxbecause the gateway could not fetch the plugin's parent configuration at request time. All plugin-bearing resource types are now resolved correctly. - Fixed issue: With
client-controlconfigured withmax_body_size: 0(no limit), a chunked request body could still be rejected withHTTP 413. Amax_body_sizeof0now correctly disables the size check for chunked requests.
Control Plane
- Fixed issue: Gateway instances could be marked OutOfSync for a short window immediately after a configuration revision changed, before the next heartbeat reported the new revision. A grace period now keeps recently heartbeating instances Healthy during that normal synchronization window.
- Fixed issue: Compatibility reports were capped at 200 unordered items, so large reports could hide errors and differ between gateway instances. The Control Plane now stores the full sorted report and computes compatibility from all items.
- Fixed issue: A secret provider request body could match a different provider type than the provider named in the URL path, causing the Data Plane to discard or misread the stored secret. The Control Plane now validates the body against the selected provider type.
- Fixed issue: The Control Plane accepted some core resource configurations that the Data Plane silently discarded, including invalid TLS, filter, and IP match configurations. These are now rejected by validation before publishing.
- Fixed issue: Plugin configurations on the runtime services endpoint were not validated, so a service with an invalid plugin configuration was accepted and then silently discarded by the Data Plane. Service plugin configurations are now validated and rejected with
HTTP 400when invalid. - Fixed issue: IPv6 upstream node hosts were rejected by the OpenAPI schema. IPv6 hosts are now accepted.
- Fixed issue: Batch
sslsvalidation used the SNI schema instead of the SSL schema, so entries without required certificate fields could pass validation. Batch SSL validation now uses the correct schema. - Fixed issue: Audit log export returned only the first 256 rows. Exports now include all matching audit logs.
- Fixed issue: Credential lookup indexes could be dropped by components that do not run database migration, and some startup schema repairs rebuilt current indexes unnecessarily. Schema repair now keeps current indexes and repairs only stale shapes.
- Fixed issue: Heartbeat and instance status queries could become slow on large deployments. Additional indexes and Go-side status computation improve these lookups.