Microservices Engine (MSE) Ingress gateways support the core and common annotations of NGINX Ingress gateways, enabling seamless migration. MSE Ingress gateways also extend NGINX annotations with additional traffic governance and security protection capabilities.
If you are migrating from NGINX Ingress gateways to MSE Ingress gateways, use this page as your annotation compatibility reference. For annotations marked Compatible, no changes are required. For annotations marked Partially compatible, review the listed limitations before migrating.
Annotation feature overview
Standard Kubernetes Ingress provides only Transport Layer Security (TLS) encryption and simple routing capabilities for Layer 7 HTTP traffic. Ingress controllers typically use annotations to enhance the capabilities of Ingress for traffic governance and security protection.
Annotation support summary
NGINX Ingress annotations
| Category |
Count |
Description |
| Supported |
51 |
Cover 90% of use cases |
| No functionality impact |
15 |
No configuration required |
| To be supported |
48 |
Planned for limited scenarios |
| Unsupported |
5 |
Specific to NGINX Ingress internal implementation |
MSE extended annotations
| Category |
Count |
Description |
| Extended |
40 |
Additional annotations for traffic governance and security protection, beyond what NGINX Ingress provides |
Annotation prefixes
MSE Ingress gateways provide annotations equivalent to NGINX Ingress annotations. For example, nginx.ingress.kubernetes.io/xxx and mse.ingress.kubernetes.io/xxx share the same functionality. Use either the nginx or mse prefix based on your preference.
Exception: MSE-exclusive annotations only accept the mse prefix. The nginx prefix cannot replace the mse prefix for these annotations.
Annotation scope
| Scope |
Effect |
| Ingress |
Applies to the routing rules defined on the Ingress resource |
| Domain name |
Applies to the hosts defined by the Ingress resource, including the same hosts on other Ingress resources |
| Service |
Applies to the services defined by the Ingress resource, including the same services on other Ingress resources |
Traffic governance
Canary release
Use these annotations together to split traffic across service versions.
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/canary |
Ingress |
Compatible |
Enables canary release. Set to true to mark this Ingress as a canary Ingress. |
nginx.ingress.kubernetes.io/canary-by-header |
Ingress |
Compatible |
Request header key used for traffic splitting. |
nginx.ingress.kubernetes.io/canary-by-header-value |
Ingress |
Compatible |
Request header value for traffic splitting. Supports exact match. |
nginx.ingress.kubernetes.io/canary-by-header-pattern |
Ingress |
Compatible |
Request header value for traffic splitting. Supports regular expression match. |
mse.ingress.kubernetes.io/canary-by-query |
Ingress |
MSE-exclusive |
URL query parameter key used for traffic splitting. |
mse.ingress.kubernetes.io/canary-by-query-value |
Ingress |
MSE-exclusive |
URL query parameter value for traffic splitting. Supports exact match. |
mse.ingress.kubernetes.io/canary-by-query-pattern |
Ingress |
MSE-exclusive |
URL query parameter value for traffic splitting. Supports regular expression match. |
nginx.ingress.kubernetes.io/canary-by-cookie |
Ingress |
Compatible |
Request cookie key used for traffic splitting. |
mse.ingress.kubernetes.io/canary-by-cookie-value |
Ingress |
MSE-exclusive (requires gateway V1.2.30 or later) |
Request cookie value for traffic splitting. Supports exact match. |
nginx.ingress.kubernetes.io/canary-weight |
Ingress |
Compatible |
Service weight for traffic splitting. |
nginx.ingress.kubernetes.io/canary-weight-total |
Ingress |
Compatible |
Total weight across all services. |
Multi-service routing
Route traffic to multiple backend services from a single Ingress by weight. After configuring this annotation, it overrides the destination service for all routing rules on the Ingress.
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/destination |
Ingress |
MSE-exclusive |
Weight-based service distribution. Format: {weight}% {serviceName}.{serviceNamespace}.svc.cluster.local:{port}. If the syntax is invalid, the annotation is ignored and the original routing rules remain unchanged. |
Example:
annotations:
# Route 60% of traffic to foo and 40% to bar.
mse.ingress.kubernetes.io/destination: |
60% foo.default.svc.cluster.local:8080
40% bar.default.svc.cluster.local:9090
Service subset
Route requests to a specific subset of Pods within a service. This is useful when one service manages multiple deployments with different labels.
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/service-subset |
Ingress |
MSE-exclusive (requires gateway V1.2.25 or later) |
Specifies the subset to route requests to. See subset routing rules below. |
mse.ingress.kubernetes.io/subset-labels |
Ingress |
MSE-exclusive (requires gateway V1.2.25 or later) |
(Optional) Label selector used to classify Pods into subsets. Use with service-subset. |
Subset routing rules:
-
If subset-labels is not configured, routing is based on the service-subset value:
-
"" or base → Pods with label opensergo.io/canary: "", or Pods without any opensergo.io/canary-prefixed label.
-
Any other value (e.g., gray) → Pods with label opensergo.io/canary-gray: gray.
-
If subset-labels is configured, requests are forwarded only to Pods matching the specified Key:Value labels.
If no Pods match the specified label, requests are automatically forwarded to all Pods in the service.
Fallback service
Redirect requests to a fallback service when the primary backend becomes unavailable.
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/default-backend |
Ingress |
Compatible |
Fallback service to receive requests when no healthy nodes are available for the primary service. |
nginx.ingress.kubernetes.io/custom-http-errors |
Ingress |
Compatible |
Works with default-backend. When a backend returns one of the specified HTTP status codes, the original request is forwarded to the fallback service. |
Important
When a request is forwarded to the fallback service, the request path is rewritten to /. This behavior matches NGINX Ingress gateways.
Regex match
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/use-regex |
Ingress |
Compatible |
Enables regular expression matching for the path defined in an Ingress. Uses RE2 syntax. |
Rewrite
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/rewrite-target |
Ingress |
Compatible |
Destination path for the rewrite operation. Capture groups are supported. |
nginx.ingress.kubernetes.io/upstream-vhost |
Ingress |
Compatible |
Overrides the Host header value when a matched request is forwarded to the backend service. |
Redirect
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/ssl-redirect |
Ingress |
Compatible |
Redirects HTTP requests to HTTPS. |
nginx.ingress.kubernetes.io/force-ssl-redirect |
Ingress |
Compatible |
Forces HTTP-to-HTTPS redirect. |
nginx.ingress.kubernetes.io/permanent-redirect |
Ingress |
Compatible |
Destination URL for a permanent redirect. |
nginx.ingress.kubernetes.io/permanent-redirect-code |
Ingress |
Compatible |
HTTP status code for the permanent redirect. |
nginx.ingress.kubernetes.io/temporal-redirect |
Ingress |
Compatible |
Destination URL for a temporary redirect. |
nginx.ingress.kubernetes.io/app-root |
Ingress |
Compatible |
Redirects requests from / to the specified application root path. |
CORS
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/enable-cors |
Ingress |
Compatible |
Enables cross-origin resource sharing (CORS). |
nginx.ingress.kubernetes.io/cors-allow-origin |
Ingress |
Compatible |
Allowed third-party origins for CORS. |
nginx.ingress.kubernetes.io/cors-allow-methods |
Ingress |
Compatible |
Allowed HTTP methods for CORS requests (e.g., GET, POST, PUT). |
nginx.ingress.kubernetes.io/cors-allow-headers |
Ingress |
Compatible |
Allowed request headers for CORS. |
nginx.ingress.kubernetes.io/cors-expose-headers |
Ingress |
Compatible |
Response headers exposed to browsers. |
nginx.ingress.kubernetes.io/cors-allow-credentials |
Ingress |
Compatible |
Specifies whether credentials can be included in CORS requests. |
nginx.ingress.kubernetes.io/cors-max-age |
Ingress |
Compatible |
Maximum duration (in seconds) to cache preflight results. |
Header control
Header control policies for base routes and canary routes are independent. Configure them separately to apply different header manipulation rules to base traffic and canary traffic.
All header control annotations are MSE-exclusive with Ingress scope. Use a YAML block literal (|) to configure multiple headers, with each key: value pair on its own line.
| Annotation |
Description |
mse.ingress.kubernetes.io/request-header-control-add |
Adds a header to requests forwarded to the backend service. If the header already exists, the new value is appended to the original value. |
mse.ingress.kubernetes.io/request-header-control-update |
Modifies a header in requests forwarded to the backend service. If the header already exists, the new value overwrites the original value. |
mse.ingress.kubernetes.io/request-header-control-remove |
Removes headers from requests. Specify a single key or multiple keys separated by commas (,). |
mse.ingress.kubernetes.io/response-header-control-add |
Adds a header to responses received from the backend service before forwarding to the client. If the header already exists, the new value is appended. |
mse.ingress.kubernetes.io/response-header-control-update |
Modifies a header in responses received from the backend service. If the header already exists, the new value overwrites the original. |
mse.ingress.kubernetes.io/response-header-control-remove |
Removes headers from responses. Specify a single key or multiple keys separated by commas (,). |
Example — multiple request headers:
annotations:
mse.ingress.kubernetes.io/request-header-control-add: |
x-custom-header: value1
x-another-header: value2
mse.ingress.kubernetes.io/request-header-control-remove: x-remove-me,x-also-remove
Timeout
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/timeout |
Ingress |
MSE-exclusive |
Request timeout in seconds. No timeout is configured by default. |
Timeout applies at the application layer (HTTP), not at the TCP transport layer.
Retry
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/proxy-next-upstream-tries |
Ingress |
Compatible |
Maximum number of retries. Default: 3. |
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout |
Ingress |
Compatible |
Timeout for retry attempts in seconds. No timeout is configured by default. |
nginx.ingress.kubernetes.io/proxy-next-upstream |
Ingress |
Compatible |
Conditions that trigger a retry. See NGINX retry conditions. |
Traffic mirroring
Mirror a percentage of live traffic to a shadow service for testing without affecting production responses.
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/mirror-target-service |
Ingress |
MSE-exclusive |
Destination service for mirrored traffic. Format: namespace/name:port. The namespace and port fields are optional; namespace defaults to the Ingress gateway namespace and port defaults to the first port. |
mse.ingress.kubernetes.io/mirror-percentage |
Ingress |
MSE-exclusive (requires gateway V1.2.32 or later) |
Percentage of traffic to mirror. Valid values: 0–100. Default: 100. |
Domain alias
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/server-alias |
Domain name |
Partially compatible (requires gateway V1.2.30 or later; only exact-match and wildcard domains are supported) |
Domain alias for the host defined in the Ingress spec. The alias shares the TLS, routing, and traffic governance configuration of the source domain. |
Single-gateway throttling (to be deprecated)
These single-gateway throttling annotations are to be deprecated. Use the global throttling annotations instead.
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/route-limit-rpm |
Ingress |
MSE-exclusive |
Maximum requests per minute (RPM) per gateway. Burst limit = value × route-limit-burst-multiplier. Response body when triggered: local_rate_limited. Status code: 503 (gateway earlier than V1.2.23) or 429 (gateway V1.2.23 or later). |
mse.ingress.kubernetes.io/route-limit-rps |
Ingress |
MSE-exclusive |
Maximum requests per second (RPS) per gateway. Burst limit = value × route-limit-burst-multiplier. Response body when triggered: local_rate_limited. Status code: 503 (gateway earlier than V1.2.23) or 429 (gateway V1.2.23 or later). |
mse.ingress.kubernetes.io/route-limit-burst-multiplier |
Ingress |
MSE-exclusive |
Multiplier for burst limits. Default: 5. |
Global throttling (recommended)
These annotations require gateway V1.2.25 or later. rate-limit-fallback-custom-response-code and rate-limit-fallback-redirect-url are mutually exclusive — specify only one.
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/rate-limit |
Ingress |
MSE-exclusive |
Maximum RPS for the route. Used for global throttling. |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-code |
Ingress |
MSE-exclusive |
HTTP status code returned when throttling is triggered. Default: 429. Mutually exclusive with rate-limit-fallback-redirect-url. |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body-type |
Ingress |
MSE-exclusive |
Response body format when throttling is triggered. text → text/plain; charset=UTF-8. json → application/json; charset=UTF-8. Default: text. |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body |
Ingress |
MSE-exclusive |
Response body content when throttling is triggered. Default: sentinel rate limited. |
mse.ingress.kubernetes.io/rate-limit-fallback-redirect-url |
Ingress |
MSE-exclusive |
Redirect URL when throttling is triggered. Mutually exclusive with rate-limit-fallback-custom-response-code. |
Example — return a custom JSON error on throttling:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-code: "429"
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body-type: json
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body: '{"error":"rate limit exceeded"}'
Global concurrency control
These annotations require gateway V1.2.25 or later. concurrency-limit-fallback-custom-response-code and concurrency-limit-fallback-redirect-url are mutually exclusive — specify only one.
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/concurrency-limit |
Ingress |
MSE-exclusive |
Maximum number of concurrent requests for the route. |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-code |
Ingress |
MSE-exclusive |
HTTP status code returned when concurrency control is triggered. Default: 429. Mutually exclusive with concurrency-limit-fallback-redirect-url. |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body-type |
Ingress |
MSE-exclusive |
Response body format when concurrency control is triggered. text → text/plain; charset=UTF-8. json → application/json; charset=UTF-8. Default: text. |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body |
Ingress |
MSE-exclusive |
Response body content when concurrency control is triggered. Default: sentinel rate limited. |
mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url |
Ingress |
MSE-exclusive |
Redirect URL when concurrency control is triggered. Mutually exclusive with concurrency-limit-fallback-custom-response-code. |
Backend protocol
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/backend-protocol |
Service |
Partially compatible (AJP and FCGI are not supported) |
Protocol used by backend services. Default: HTTP. Valid values: HTTP, HTTP2, HTTPS, gRPC, gRPCS. |
Load balancing
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/load-balance |
Service |
Partially compatible (Exponentially Weighted Moving Average (EWMA) is not supported; falls back to round-robin) |
Load balancing algorithm for backend services. Default: round_robin. Valid values: round_robin (round-robin), least_conn (least connections), random. |
nginx.ingress.kubernetes.io/upstream-hash-by |
Service |
Partially compatible (combining NGINX variables and constants is not supported) |
Consistent hashing algorithm. Supported hash keys: $request_uri (request path including parameters), $host (request host), $remote_addr (client IP address), $http_<headerName> (request header value), $arg_<varName> (URL query parameter value). |
Service prefetching (graceful start)
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/warmup |
Service |
MSE-exclusive |
Warm-up duration in seconds. By default, the service prefetching feature is disabled. |
Important
Service prefetching requires round-robin or least connections as the load balancing algorithm. It is not supported with other algorithms.
Cookie affinity
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/affinity |
Service |
Compatible |
Affinity type. The only valid value is cookie. |
nginx.ingress.kubernetes.io/affinity-mode |
Service |
Partially compatible (persistent mode is not supported) |
Affinity mode. The only valid value is balanced. |
nginx.ingress.kubernetes.io/session-cookie-name |
Service |
Compatible |
Cookie name used as the hash key for session affinity. |
nginx.ingress.kubernetes.io/session-cookie-path |
Service |
Compatible |
Path set on the generated session cookie. Default: /. |
nginx.ingress.kubernetes.io/session-cookie-max-age |
Service |
Compatible |
Maximum age of the generated session cookie in seconds. Default: session-level (no Max-Age set). |
nginx.ingress.kubernetes.io/session-cookie-expires |
Service |
Compatible |
Expiration time of the generated session cookie in seconds. Default: session-level (no Expires set). |
IP address-based access control
Route-level access control takes precedence over domain-level access control. Within route-level policies, denylist-source-range takes precedence over blacklist-source-range.
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/whitelist-source-range |
Ingress |
Compatible |
IP address whitelist for a route. Accepts IP addresses and CIDR blocks, separated by commas. |
nginx.ingress.kubernetes.io/denylist-source-range |
Ingress |
Compatible (requires gateway V1.2.31 or later) |
IP address blacklist for a route. Accepts IP addresses and CIDR blocks, separated by commas. Takes precedence over mse.ingress.kubernetes.io/blacklist-source-range. |
mse.ingress.kubernetes.io/blacklist-source-range |
Ingress |
MSE-exclusive |
IP address blacklist for a route. Accepts IP addresses and CIDR blocks, separated by commas. |
mse.ingress.kubernetes.io/domain-whitelist-source-range |
Ingress |
MSE-exclusive |
IP address whitelist applied at the domain level. Route-level whitelists take precedence. |
mse.ingress.kubernetes.io/domain-blacklist-source-range |
Ingress |
MSE-exclusive |
IP address blacklist applied at the domain level. Route-level blacklists take precedence. |
Connection pool (gateway to backend)
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection |
Service |
MSE-exclusive |
Maximum total TCP connections between the gateway and the backend service. |
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint |
Service |
MSE-exclusive |
Maximum TCP connections between the gateway and a single backend endpoint. |
mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connection |
Service |
MSE-exclusive |
Maximum HTTP requests per TCP connection between the gateway and the backend service. |
Security protection
Client-to-gateway TLS
| Annotation |
Scope |
Support status |
Description |
mse.ingress.kubernetes.io/tls-min-protocol-version |
Domain name |
MSE-exclusive |
Minimum TLS version. Default: TLSv1.0. Valid values: TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3. |
mse.ingress.kubernetes.io/tls-max-protocol-version |
Domain name |
MSE-exclusive |
Maximum TLS version. Default: TLSv1.3. Valid values: TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3. |
nginx.ingress.kubernetes.io/ssl-cipher |
Domain name |
Compatible |
TLS cipher suites, separated by commas. Applies only during TLS 1.0–1.2 handshakes. Default cipher suites: ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-SHA, ECDHE-RSA-AES128-SHA, AES128-GCM-SHA256, AES128-SHA, ECDHE-ECDSA-AES256-GCM-SHA384, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-SHA, ECDHE-RSA-AES256-SHA, AES256-GCM-SHA384, AES256-SHA. |
mse.ingress.kubernetes.io/auth-tls-secret |
Domain name |
Partially compatible (secret name must follow the format <domain-cert-secret-name>-cacert) |
CA certificate the gateway uses to verify the client certificate during a mutual TLS (mTLS) handshake. |
Example — enforce TLS 1.2 or later with a specific cipher suite:
annotations:
mse.ingress.kubernetes.io/tls-min-protocol-version: TLSv1.2
mse.ingress.kubernetes.io/tls-max-protocol-version: TLSv1.3
nginx.ingress.kubernetes.io/ssl-cipher: ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-GCM-SHA384
Gateway-to-backend TLS
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/proxy-ssl-secret |
Service |
Compatible |
Client certificate the gateway presents to the backend service for mutual authentication. |
nginx.ingress.kubernetes.io/proxy-ssl-name |
Service |
Compatible |
Server Name Indication (SNI) value sent during the TLS handshake to the backend service. |
nginx.ingress.kubernetes.io/proxy-ssl-server-name |
Service |
Compatible |
Enables SNI during the TLS handshake to the backend service. |
Authentication
MSE Ingress supports HTTP basic authentication. Use these annotations together: configure the secret name, format, and optional realm.
| Annotation |
Scope |
Support status |
Description |
nginx.ingress.kubernetes.io/auth-type |
Ingress |
Partially compatible (only basic is supported) |
Authentication type. |
nginx.ingress.kubernetes.io/auth-secret |
Ingress |
Compatible |
Kubernetes Secret containing the credentials. Format: <namespace>/<name>. |
nginx.ingress.kubernetes.io/auth-secret-type |
Ingress |
Compatible |
Secret data format. auth-file: the auth key holds newline-separated username:password entries. auth-map: each key is a username and its value is the password. |
nginx.ingress.kubernetes.io/auth-realm |
Ingress |
Compatible |
Authentication realm. Credentials are shared across routes in the same realm. |
For more information about NGINX Ingress annotations, see Annotations.