All Products
Search
Document Center

Microservices Engine:Annotations supported by MSE Ingress gateways

Last Updated:Mar 11, 2026

Microservices Engine (MSE) Ingress gateways are compatible with most NGINX Ingress annotations and provide 40 additional annotations for traffic governance and security. If you are migrating from NGINX Ingress, most annotations work without changes.

Compatibility summary

CategoryCountDetails
Supported NGINX Ingress annotations51Cover 90% of common use cases
No-op annotations15No configuration required
To-be-supported annotations48Planned for future releases
Unsupported annotations5Tied to NGINX-specific code snippets
MSE-exclusive annotations40Extended traffic governance and security

Annotation basics

Scope

Each annotation applies at one of three levels:

ScopeApplies toCross-Ingress behavior
IngressRouting rules in the Ingress resourceScoped to the current Ingress only
Domain nameHosts defined in the Ingress resourceAlso takes effect on the same hosts in other Ingress resources
ServiceBackend services defined in the Ingress resourceAlso takes effect on the same services in other Ingress resources

Prefixes

MSE Ingress gateways accept both nginx.ingress.kubernetes.io/ and mse.ingress.kubernetes.io/ prefixes for compatible annotations. Use either prefix based on your preference.

MSE-exclusive annotations support only the mse.ingress.kubernetes.io/ prefix.

Annotation value formats

Kubernetes annotations are always strings. The following encoding conventions apply:

TypeFormatExample
Boolean"true" or "false""true"
IntegerQuoted number"3"
DurationQuoted number (seconds)"30"
PercentageQuoted number (0-100)"80"
String listComma-separated"192.168.0.1,10.0.0.0/8"
Multi-lineYAML pipe (|)See header control examples

Precedence and interaction rules

RuleDetails
Prefix equivalencenginx.ingress.kubernetes.io/xxx and mse.ingress.kubernetes.io/xxx have identical behavior for compatible annotations
Route over domainRoute-level IP lists take precedence over domain-level IP lists
NGINX denylist over MSE denylistnginx.ingress.kubernetes.io/denylist-source-range takes precedence over mse.ingress.kubernetes.io/blacklist-source-range
Mutually exclusive rate-limit fallbacksrate-limit-fallback-custom-response-code and rate-limit-fallback-redirect-url cannot be used together
Mutually exclusive concurrency fallbacksconcurrency-limit-fallback-custom-response-code and concurrency-limit-fallback-redirect-url cannot be used together
Independent header controlHeader control annotations for base routes and canary routes are validated independently

Compatibility notes

  • NGINX variables: MSE implements features differently from NGINX. NGINX variables configured in annotations or code snippets are incompatible with MSE.

  • proxy-body-size behavior: MSE cloud-native gateways use chunked transfer encoding, which automatically breaks large request bodies into chunks. To handle large file transfers, adjust the DownstreamConnectionBufferLimits parameter in Parameter Settings for your MSE gateway.

Traffic governance

Canary release

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/canaryIngressCompatibleEnable canary release.
nginx.ingress.kubernetes.io/canary-by-headerIngressCompatibleSet the request header key for traffic splitting.
nginx.ingress.kubernetes.io/canary-by-header-valueIngressCompatibleSet the request header value for traffic splitting. Supports exact match.
nginx.ingress.kubernetes.io/canary-by-header-patternIngressCompatibleSet the request header value for traffic splitting. Supports regex match.
nginx.ingress.kubernetes.io/canary-by-cookieIngressCompatibleSet the request cookie key for traffic splitting.
nginx.ingress.kubernetes.io/canary-weightIngressCompatibleSet the service weight for traffic splitting.
nginx.ingress.kubernetes.io/canary-weight-totalIngressCompatibleSet the total weight.
mse.ingress.kubernetes.io/canary-by-queryIngressMSE-exclusiveSet the URL query parameter for traffic splitting.
mse.ingress.kubernetes.io/canary-by-query-valueIngressMSE-exclusiveSet the URL query parameter value for traffic splitting. Supports exact match.
mse.ingress.kubernetes.io/canary-by-query-patternIngressMSE-exclusiveSet the URL query parameter value for traffic splitting. Supports regex match.
mse.ingress.kubernetes.io/canary-by-cookie-valueIngressMSE-exclusive (V1.2.30+)Set the request cookie value for traffic splitting. Supports exact match.
# Canary release: route traffic based on a header value
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "x-canary"
    nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: my-service-canary
                port:
                  number: 80

Multi-service routing

Route traffic to multiple backend services with weight-based distribution.

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/destinationIngressMSE-exclusiveDefine weight-based service distribution for routes.

Syntax: {weight}% {serviceName}.{serviceNamespace}.svc.cluster.local:{port}

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
After you configure this annotation, all routing rules on the Ingress are directed to the specified services. If the syntax is invalid, the annotation is ignored and the original routing rules remain unchanged.

Service subset

Route traffic to a subset of pods within a service, useful when one service manages multiple deployments.

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/service-subsetIngressMSE-exclusive (V1.2.25+)Set the service subset for targeted pod routing.
mse.ingress.kubernetes.io/subset-labelsIngressMSE-exclusive (V1.2.25+)Optional. Set the labels used to classify pods into subsets.

How service-subset routes traffic:

  • Without subset-labels configured:

    • Set to "" or base: Routes to pods labeled opensergo.io/canary: "" or pods without the opensergo.io/canary label key.

    • Set to any other value (e.g., gray): Routes to pods labeled opensergo.io/canary-gray: gray.

  • With subset-labels configured: Routes only to pods whose labels match the Key:Value pairs defined in subset-labels.

If no pods match the specified label, traffic is automatically routed to all pods in the service.
annotations:
  # Route traffic to pods labeled as "gray" subset
  mse.ingress.kubernetes.io/service-subset: "gray"

Fallback

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/default-backendIngressCompatibleSet the fallback service. Requests are forwarded to this service when no healthy nodes are available for the primary service.
nginx.ingress.kubernetes.io/custom-http-errorsIngressCompatibleUsed with default-backend. Forward the request to the fallback service when the backend returns a specified HTTP status code.
Important

When a request is forwarded to the fallback service, the request path is rewritten to /. This behavior is consistent with NGINX Ingress gateways.

Regex match

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/use-regexIngressCompatibleEnable regular expression matching for the Ingress path. Uses RE2 syntax.

Rewrite

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/rewrite-targetIngressCompatibleSet the target path for a rewrite. Capture groups are supported.
nginx.ingress.kubernetes.io/upstream-vhostIngressCompatibleOverride the Host header when forwarding requests to a backend service.

Redirect

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/ssl-redirectIngressCompatibleRedirect HTTP to HTTPS.
nginx.ingress.kubernetes.io/force-ssl-redirectIngressCompatibleForce redirect HTTP to HTTPS.
nginx.ingress.kubernetes.io/permanent-redirectIngressCompatibleSet a permanent redirect URL.
nginx.ingress.kubernetes.io/permanent-redirect-codeIngressCompatibleSet the status code for a permanent redirect.
nginx.ingress.kubernetes.io/temporal-redirectIngressCompatibleSet a temporary redirect URL.
nginx.ingress.kubernetes.io/app-rootIngressCompatibleRedirect requests from / to a specified application root path.
Some NGINX Ingress versions support NGINX variables for redirection, but this is not documented in the official Annotations reference and may cause incompatibility issues. Avoid using NGINX variables for redirection.

CORS

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/enable-corsIngressCompatibleEnable cross-origin resource sharing (CORS).
nginx.ingress.kubernetes.io/cors-allow-originIngressCompatibleSet the allowed origins.
nginx.ingress.kubernetes.io/cors-allow-methodsIngressCompatibleSet the allowed HTTP methods (GET, POST, PUT, etc.).
nginx.ingress.kubernetes.io/cors-allow-headersIngressCompatibleSet the allowed request headers.
nginx.ingress.kubernetes.io/cors-expose-headersIngressCompatibleSet the response headers exposed to browsers.
nginx.ingress.kubernetes.io/cors-allow-credentialsIngressCompatibleAllow credentials in CORS requests.
nginx.ingress.kubernetes.io/cors-max-ageIngressCompatibleSet the maximum duration (in seconds) for caching preflight results.

Header control

Manipulate request and response headers at the gateway level. Header control annotations for base routes and canary routes are independent -- configure different header policies for each.

Request headers:

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/request-header-control-addIngressMSE-exclusiveAppend a header to requests forwarded to the backend. If the header already exists, the new value is appended to the original value.
mse.ingress.kubernetes.io/request-header-control-updateIngressMSE-exclusiveOverwrite a header in requests forwarded to the backend. If the header already exists, the original value is replaced.
mse.ingress.kubernetes.io/request-header-control-removeIngressMSE-exclusiveRemove a header from requests forwarded to the backend.

Response headers:

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/response-header-control-addIngressMSE-exclusiveAppend a header to responses before forwarding to the client. If the header already exists, the new value is appended.
mse.ingress.kubernetes.io/response-header-control-updateIngressMSE-exclusiveOverwrite a header in responses before forwarding to the client. If the header already exists, the original value is replaced.
mse.ingress.kubernetes.io/response-header-control-removeIngressMSE-exclusiveRemove a header from responses before forwarding to the client.

Syntax for add and update annotations:

  • Single header: key value

  • Multiple headers: Use a YAML pipe (|), one key-value pair per line.

Syntax for remove annotations:

  • Single header: key

  • Multiple headers: Separate with commas (,).

annotations:
  # Add a custom header to requests
  mse.ingress.kubernetes.io/request-header-control-add: "x-request-id 12345"
  # Add multiple headers to responses
  mse.ingress.kubernetes.io/response-header-control-add: |
    x-custom-header value1
    x-another-header value2
  # Remove headers from responses
  mse.ingress.kubernetes.io/response-header-control-remove: "x-powered-by,server"

Timeout

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/timeoutIngressMSE-exclusiveSet the request timeout in seconds. No timeout is configured by default.
This timeout applies at the application layer, not at the TCP transport layer.
annotations:
  mse.ingress.kubernetes.io/timeout: "30"

Retry

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/proxy-next-upstream-triesIngressCompatibleSet the maximum number of retry attempts. Default: 3.
nginx.ingress.kubernetes.io/proxy-next-upstream-timeoutIngressCompatibleSet the timeout for retries in seconds. No timeout by default.
nginx.ingress.kubernetes.io/proxy-next-upstreamIngressCompatibleDefine retry conditions. See NGINX retry mechanism.

Traffic mirroring

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/mirror-target-serviceIngressMSE-exclusiveSet the service that receives mirrored traffic. Format: namespace/name:port.
mse.ingress.kubernetes.io/mirror-percentageIngressMSE-exclusive (V1.2.32+)Set the percentage of traffic to mirror. Valid values: 0-100. Default: 100.

mirror-target-service parameters:

ParameterRequiredDescription
namespaceNoNamespace of the Kubernetes Service. Defaults to the namespace of the Ingress gateway.
nameYesName of the Kubernetes Service.
portNoService port for mirrored traffic. Defaults to the first port.
annotations:
  # Mirror 50% of traffic to a shadow service
  mse.ingress.kubernetes.io/mirror-target-service: "default/shadow-service:8080"
  mse.ingress.kubernetes.io/mirror-percentage: "50"

Domain alias

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/server-aliasDomain namePartially compatible (V1.2.30+)Set domain aliases for the domains defined in the Ingress spec. Domain aliases share the TLS, routing, and traffic governance configurations of the source domain. Only exact match and wildcard domains are supported.

Rate limiting

Global rate limiting (recommended)

Use global rate limiting for consistent traffic control across all gateway instances.

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/rate-limitIngressMSE-exclusive (V1.2.25+)Set the maximum requests per second (RPS) for a route.
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-codeIngressMSE-exclusive (V1.2.25+)Set the response code when rate limiting is triggered. Default: 429. Mutually exclusive with rate-limit-fallback-redirect-url.
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body-typeIngressMSE-exclusive (V1.2.25+)Set the response body format. Default: text. text sets Content-Type to text/plain; charset=UTF-8. JSON sets it to application/json; charset=UTF-8.
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-bodyIngressMSE-exclusive (V1.2.25+)Set the response body text. Default: sentinel rate limited.
mse.ingress.kubernetes.io/rate-limit-fallback-redirect-urlIngressMSE-exclusive (V1.2.25+)Redirect to a URL when rate limiting is triggered. Mutually exclusive with rate-limit-fallback-custom-response-code.
annotations:
  # Limit to 100 RPS with a custom JSON response
  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"}'

Single-gateway rate limiting (to be deprecated)

Important

Single-gateway rate limiting is to be deprecated. Use global rate limiting instead.

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/route-limit-rpmIngressMSE-exclusiveSet the maximum requests per minute (RPM) for a route on a single gateway. Burst limit = RPM x route-limit-burst-multiplier.
mse.ingress.kubernetes.io/route-limit-rpsIngressMSE-exclusiveSet the maximum requests per second (RPS) for a route on a single gateway. Burst limit = RPS x route-limit-burst-multiplier.
mse.ingress.kubernetes.io/route-limit-burst-multiplierIngressMSE-exclusiveSet the burst limit multiplier. Default: 5.

When rate limiting is triggered:

  • Response body: local_rate_limited

  • Gateway versions earlier than V1.2.23: returns status code 503

  • Gateway versions V1.2.23 and later: returns status code 429

Concurrency control

Global concurrency control limits the number of requests processed simultaneously on a route.

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/concurrency-limitIngressMSE-exclusive (V1.2.25+)Set the maximum concurrent requests for a route.
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-codeIngressMSE-exclusive (V1.2.25+)Set the response code 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-typeIngressMSE-exclusive (V1.2.25+)Set the response body format. Default: text. text sets Content-Type to text/plain; charset=UTF-8. JSON sets it to application/json; charset=UTF-8.
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-bodyIngressMSE-exclusive (V1.2.25+)Set the response body text. Default: sentinel rate limited.
mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-urlIngressMSE-exclusive (V1.2.25+)Redirect to a URL when concurrency control is triggered. Mutually exclusive with concurrency-limit-fallback-custom-response-code.
annotations:
  # Limit to 50 concurrent requests with a redirect on overflow
  mse.ingress.kubernetes.io/concurrency-limit: "50"
  mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url: "https://example.com/busy"

Backend protocol

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/backend-protocolServicePartially compatibleSet the protocol for backend services. Default: HTTP. Valid values: HTTP, HTTP2, HTTPS, gRPC, gRPCS. AJP and FCGI are not supported.

Load balancing

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/load-balanceServicePartially compatibleSet the load balancing algorithm. Default: round_robin. Valid values: round_robin, least_conn, random. The Exponentially Weighted Moving Average (EWMA) algorithm is not supported. If EWMA is configured, the algorithm falls back to round_robin.
nginx.ingress.kubernetes.io/upstream-hash-byServicePartially compatibleEnable consistent hashing. Combining NGINX variables with constants is not supported.

Supported consistent hashing methods:

  • NGINX variables: $request_uri (request path including parameters), $host (request host), $remote_addr (client IP address)

  • Request headers: $http_headerName

  • Request path parameters: $arg_varName

Graceful start (service prefetching)

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/warmupServiceMSE-exclusiveSet the warm-up duration in seconds. Disabled by default.
Important

Graceful start only works with the round_robin and least_conn load balancing algorithms.

annotations:
  # Warm up new pods over 60 seconds
  mse.ingress.kubernetes.io/warmup: "60"

Cookie affinity

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/affinityServiceCompatibleSet the affinity type. The only valid value is cookie.
nginx.ingress.kubernetes.io/affinity-modeServicePartially compatibleSet the affinity mode. The only valid value is balanced. The persistent mode is not supported.
nginx.ingress.kubernetes.io/session-cookie-nameServiceCompatibleSet the name of the cookie used as the hash key.
nginx.ingress.kubernetes.io/session-cookie-pathServiceCompatibleSet the path of the generated cookie. Default: /.
nginx.ingress.kubernetes.io/session-cookie-max-ageServiceCompatibleSet the cookie expiration time in seconds. Defaults to session-level expiration.
nginx.ingress.kubernetes.io/session-cookie-expiresServiceCompatibleSet the cookie expiration time in seconds. Defaults to session-level expiration.

IP access control

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/whitelist-source-rangeIngressCompatibleSet the IP allowlist for a route. Supports IP addresses and CIDR blocks, separated by commas.
nginx.ingress.kubernetes.io/denylist-source-rangeIngressCompatible (V1.2.31+)Set the IP denylist for a route. Supports IP addresses and CIDR blocks, separated by commas.
mse.ingress.kubernetes.io/blacklist-source-rangeIngressMSE-exclusiveSet the IP denylist for a route. Supports IP addresses and CIDR blocks, separated by commas.
mse.ingress.kubernetes.io/domain-whitelist-source-rangeIngressMSE-exclusiveSet the IP allowlist for a domain name. Supports IP addresses and CIDR blocks, separated by commas.
mse.ingress.kubernetes.io/domain-blacklist-source-rangeIngressMSE-exclusiveSet the IP denylist for a domain name. Supports IP addresses and CIDR blocks, separated by commas.

Precedence rules:

  • Route-level IP lists take precedence over domain-level IP lists.

  • nginx.ingress.kubernetes.io/denylist-source-range takes precedence over mse.ingress.kubernetes.io/blacklist-source-range.

annotations:
  # Allow only specific IPs at the route level
  nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.1.100"

Gateway-to-backend connection pool

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/connection-policy-tcp-max-connectionServiceMSE-exclusiveSet the maximum number of TCP connections between the gateway and the backend service.
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpointServiceMSE-exclusiveSet the maximum number of TCP connections between the gateway and each backend endpoint.
mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connectionServiceMSE-exclusiveSet the maximum number of HTTP requests per connection between the gateway and the backend service.
annotations:
  # Limit connection pool to backend
  mse.ingress.kubernetes.io/connection-policy-tcp-max-connection: "1024"
  mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint: "100"
  mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connection: "500"

Security protection

Client-to-gateway TLS

AnnotationScopeStatusDescription
mse.ingress.kubernetes.io/tls-min-protocol-versionDomain nameMSE-exclusiveSet the minimum TLS version. Default: TLSv1.0. Valid values: TLSv1.0, TLSv1.1, TLSv1.2.
mse.ingress.kubernetes.io/tls-max-protocol-versionDomain nameMSE-exclusiveSet the maximum TLS version. Recommended: TLSv1.2. Valid values: TLSv1.0, TLSv1.1, TLSv1.2.
nginx.ingress.kubernetes.io/ssl-cipherDomain nameCompatibleSet the TLS cipher suites, separated by commas. Takes effect only for TLS 1.0 to 1.2 handshakes.
mse.ingress.kubernetes.io/auth-tls-secretDomain namePartially compatibleSet the CA certificate for client certificate verification during mTLS handshakes. The secret name must follow the format: {domain-cert-secret-name}-cacert.

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

annotations:
  # Enforce TLS 1.2 minimum
  mse.ingress.kubernetes.io/tls-min-protocol-version: "TLSv1.2"
  mse.ingress.kubernetes.io/tls-max-protocol-version: "TLSv1.2"

Gateway-to-backend TLS

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/proxy-ssl-secretServiceCompatibleSet the client certificate used by the gateway, allowing the backend service to authenticate the gateway.
nginx.ingress.kubernetes.io/proxy-ssl-nameServiceCompatibleSet the Server Name Indication (SNI) for the TLS handshake.
nginx.ingress.kubernetes.io/proxy-ssl-server-nameServiceCompatibleEnable SNI during the TLS handshake.

Authentication

AnnotationScopeStatusDescription
nginx.ingress.kubernetes.io/auth-typeIngressPartially compatibleSet the authentication type. Only basic is supported.
nginx.ingress.kubernetes.io/auth-secretIngressCompatibleSet the secret containing credentials. Format: <namespace>/<name>.
nginx.ingress.kubernetes.io/auth-secret-typeIngressCompatibleSet the secret format. auth-file: data key is auth, value contains username:password pairs (one per line). auth-map: data keys are usernames, values are passwords.
nginx.ingress.kubernetes.io/auth-realmIngressCompatibleSet the authentication realm. Credentials are shared within the same realm.
annotations:
  # Basic authentication with a Kubernetes secret
  nginx.ingress.kubernetes.io/auth-type: "basic"
  nginx.ingress.kubernetes.io/auth-secret: "default/my-auth-secret"
  nginx.ingress.kubernetes.io/auth-secret-type: "auth-file"
  nginx.ingress.kubernetes.io/auth-realm: "Protected Area"

See also