NGINX Ingress Migration Tool

Warning: The community-maintained kubernetes/ingress-nginx project has reached end of maintenance. v1.15.1 (March 19, 2026) is the final release — it will receive no further releases, bugfixes, or security patches. The F5 NGINX Ingress Controller (nginx/kubernetes-ingress) is actively maintained and is the recommended migration target.

Overview

This interactive guide helps you migrate from the community-maintained Kubernetes Ingress NGINX (Ingress-NGINX) controller (kubernetes/ingress-nginx) to the F5 NGINX Ingress Controller (nginx/kubernetes-ingress). It covers 130+ annotation mappings, ConfigMap key translations, and CRD migration examples across three tabs:

  • Getting Started — Background on why to migrate, CRD overviews, installation, and a migration checklist
  • Ingress NGINX Config Analyzer — Paste an Ingress manifest and get automatic migration suggestions with ready-to-use YAML
  • Reference Guide — Complete annotation and ConfigMap mapping tables with side-by-side examples

Why Migrate?

The two controllers take fundamentally different approaches to configuring NGINX in Kubernetes.

  • Kubernetes Ingress NGINX (Ingress-NGINX) is annotation-driven — it relies on annotations and ConfigMap keys to customize NGINX. These are opaque strings with no schema validation — a single Ingress resource may carry dozens of annotations as unstructured key-value pairs.
  • F5 NGINX Ingress Controller is CRD-native — it uses Custom Resource Definitions (VirtualServer, Policy, TransportServer) as its primary config model, providing structured, schema-validated YAML with IDE autocompletion.

While the F5 NGINX Ingress Controller still supports annotations for common settings, CRDs unlock capabilities that annotations cannot express:

  • Schema validation — Kubernetes validates CRD fields at apply time, catching misconfigurations before they reach NGINX
  • Structured configuration — Nested YAML objects replace long annotation strings, making complex routing, traffic splitting, and security policies readable and maintainable
  • Reusability — Policies (rate limiting, auth, WAF) are defined once and attached to any number of routes
  • Layer 4 support — TransportServer CRDs handle TCP/UDP workloads that annotations cannot express
  • IDE and tooling support — CRD schemas enable autocompletion, linting, and documentation in editors and CI pipelines

Phased Migration Strategy

Rather than performing a "big bang" cutover, F5 recommends a phased migration that allows you to validate each workload before decommissioning the community controller. Both controllers can run side-by-side in the same cluster using separate IngressClass resources.

  1. Deploy side-by-side — Install the F5 NGINX Ingress Controller alongside the community controller using a distinct IngressClass (e.g., nginx-nic). This ensures existing traffic is unaffected.
  2. Migrate service-by-service — Update each Ingress resource's ingressClassName to point to the new controller. Convert annotations as described in the Reference Guide, validate routing and TLS behavior, and promote to production before moving on to the next service.
  3. Decommission — After all workloads have been migrated and validated, remove the community controller deployment, its IngressClass, and any unused ConfigMaps.
Tip: Use the Ingress NGINX Config Analyzer tab to process each Ingress manifest during step 2. It will flag unsupported annotations and generate the equivalent F5 NGINX Ingress Controller configuration.

CRDs Summary

The F5 NGINX Ingress Controller uses Custom Resource Definitions (CRDs) to extend Kubernetes with NGINX-specific configuration. CRDs provide type-safe, validated configuration that goes beyond what standard Ingress annotations can offer.

VirtualServer CRD

The primary CRD for configuring HTTP/HTTPS load balancing. It replaces Ingress resources and provides advanced traffic management capabilities with full validation.

  • Traffic Splitting: Route percentages of traffic to different backends for canary/blue-green deployments
  • Content-Based Routing: Route based on headers, cookies, arguments, or variables
  • Path Rewriting: Modify request URIs with regex support before forwarding to backends
  • Error Pages: Custom responses for specific HTTP error codes
  • Request/Response Headers: Add, modify, or remove headers in transit
  • Health Checks: Active health monitoring of upstream servers
  • Session Persistence: Cookie-based sticky sessions

VirtualServerRoute CRD

Enables delegation of route configuration to different namespaces. Allows teams to manage their own routing rules while maintaining centralized control over the domain.

  • Cross-Namespace Routing: Reference services in different namespaces
  • Path Delegation: Delegate path prefixes to other teams/namespaces
  • Independent Updates: Teams update routes without modifying the parent VirtualServer
  • Access Control: Limit which namespaces can define routes for a host

Policy CRD

Reusable security and traffic policies that can be attached to VirtualServers or specific routes. Policies enable consistent security controls across multiple applications.

  • Rate Limiting: Limit request rates by IP, header, or custom key
  • Access Control: IP allowlists and denylists
  • Basic Auth: Username/password authentication via htpasswd
  • JWT Validation: Validate JSON Web Tokens (Plus)
  • OIDC: Native OpenID Connect integration (Plus)
  • API Key Auth: Authenticate via API keys in headers/query (Plus)
  • mTLS: Client certificate verification (ingress) and backend TLS (egress)
  • WAF: F5 WAF for NGINX web application firewall (Plus)

TransportServer CRD

Configures TCP/UDP load balancing for non-HTTP protocols. Essential for databases, message queues, gaming servers, and other Layer 4 applications.

  • TCP Load Balancing: MySQL, PostgreSQL, Redis, custom TCP services
  • UDP Load Balancing: DNS, RADIUS, gaming protocols
  • TLS Passthrough: Pass encrypted traffic directly to backends
  • Health Checks: TCP/UDP health monitoring
  • Session Persistence: IP hash-based session affinity

GlobalConfiguration CRD

Cluster-wide configuration for the F5 NGINX Ingress Controller. Defines global listeners for TCP/UDP and TLS passthrough that TransportServers can reference.

  • TCP/UDP Listeners: Define ports for non-HTTP traffic
  • TLS Passthrough Listeners: Configure SNI-based routing
  • Global Settings: Controller-wide configuration options

Installing CRDs

CRDs can be installed via Helm or manually using manifests, depending on your deployment method. See the F5 NGINX Ingress Controller installation docs for full instructions.

Helm (example)

If you install the F5 NGINX Ingress Controller via Helm, CRDs are included automatically. To ensure they are enabled:

helm install nginx-ingress oci://ghcr.io/nginx/charts/nginx-ingress --version 2.5.0 --set controller.enableCRDs=true

The controller.enableCRDs flag is true by default. If you previously disabled it, re-enable it to use CRD resources. See the Helm installation guide for details.

Manifests (example)

If you deploy using manifests, install CRDs manually before deploying the controller:

kubectl apply -f https://raw.githubusercontent.com/nginx/kubernetes-ingress/v5.4.1/deploy/crds.yaml

Replace the version number with your target controller version. See the manifest installation guide for the full step-by-step process.

Note: The crds.yaml file contains all CRDs (VirtualServer, VirtualServerRoute, Policy, TransportServer, GlobalConfiguration) in a single manifest.
Note: Replace version numbers with your target controller version.

Migration Checklist

  • Install CRDs via Helm (controller.enableCRDs=true) or manifests (deploy/crds.yaml)
  • Review annotation mappings — not all nginx.ingress.kubernetes.io/ annotations have a direct nginx.org/ equivalent (see NGINX Mappings)
  • Map rewrite-target annotation to nginx.org/rewrite-target (not nginx.org/rewrites)
  • Migrate ConfigMap keys that differ between controllers (see ConfigMap Mappings)
  • Convert HSTS ConfigMap keys to nginx.org/hsts annotations for per-Ingress control
  • Convert server-tokens ConfigMap key to nginx.org/server-tokens annotation
  • Convert access control annotations to Policy CRD (accessControl)
  • Convert authentication annotations to Policy CRD (basicAuth, jwt, oidc, apiKey)
  • Convert canary/traffic splitting to VirtualServer splits/matches
  • Convert mTLS annotations to ingressMTLS/egressMTLS policies
  • Convert CORS annotations to location-snippets or server-snippets
  • Convert custom error pages to VirtualServer errorPages
  • Convert header manipulation to VirtualServer requestHeaders/responseHeaders
  • Convert rate limiting annotations to Policy CRD (rateLimit)
  • Convert redirect annotations to VirtualServer action.redirect
  • Convert session affinity annotations to VirtualServer upstream sessionCookie
  • Convert SSL passthrough to TransportServer CRD
  • Convert TCP/UDP services to TransportServer CRD
  • Replace ssl-redirect with nginx.org/ssl-redirect (not the deprecated ingress.kubernetes.io/ssl-redirect)
  • Verify snippets (configuration-snippet, server-snippet) use F5 NGINX Ingress Controller equivalents
  • Test in staging environment
  • Update monitoring and alerting

Additional Resources

Warning: The community-maintained kubernetes/ingress-nginx project has reached end of maintenance. v1.15.1 (March 19, 2026) is the final release — it will receive no further releases, bugfixes, or security patches. The F5 NGINX Ingress Controller (nginx/kubernetes-ingress) is actively maintained and is the recommended migration target.

Ingress NGINX Config Analyzer

Paste a Kubernetes Ingress YAML manifest that uses Kubernetes Ingress NGINX (Ingress-NGINX) annotations to get migration suggestions for the F5 NGINX Ingress Controller.

Drop YAML file here
0 lines
Migration strategy:
Prefer Policy CRDs and VirtualServer, fall back to annotations when no CRD path exists
Ctrl+Enter to analyze
Warning: The community-maintained kubernetes/ingress-nginx project has reached end of maintenance. v1.15.1 (March 19, 2026) is the final release — it will receive no further releases, bugfixes, or security patches. The F5 NGINX Ingress Controller (nginx/kubernetes-ingress) is actively maintained and is the recommended migration target.

Key Differences

AspectKubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Repositorykubernetes/ingress-nginxnginx/kubernetes-ingress
Annotation Prefixnginx.ingress.kubernetes.io/nginx.org/ or nginx.com/ or appprotect.f5.com/
ConfigMap Nameingress-nginx-controllernginx-config
CRD SupportNoneVirtualServer, VirtualServerRoute, Policy, TransportServer, GlobalConfiguration
NGINX Plus SupportNoYes (with nginx.com/ annotations)
Note: Many Kubernetes Ingress NGINX (Ingress-NGINX) capabilities that do not have direct F5 NGINX Ingress Controller annotations or CRDs can still be achieved through NGINX configuration snippets (via either snippet annotations or VirtualServer/VirtualServerRoute CRDs). We recommend that users proceed with caution when using snippets, as they inject raw NGINX configuration and are intended for more advanced use cases.
New in v5.4.0 — Policy CRDs on Ingress objects: Policy CRDs (e.g. accessControl, cors) can now be referenced directly from Ingress resources using the nginx.org/policies annotation — no VirtualServer required. This is the recommended migration path for features that support it. Look for the (Recommended) tab in the mapping examples.

NGINX Mappings

These features are available in both NGINX Open Source and NGINX Plus editions. All items are annotations unless otherwise indicated with a badge (e.g. ConfigMap, Policy CRD, VirtualServer CRD). Community annotations use the nginx.ingress.kubernetes.io/ prefix; F5 NGINX Ingress Controller annotations use nginx.org/.

How to Read the Mappings
  • Annotation-to-annotation rows : Direct mappings where you change the annotation name/prefix. Click to expand and see before/after Ingress YAML examples.
  • CRD-based rows : Annotations that map to a CRD (VirtualServer, Policy, or TransportServer). Click to expand for full CRD examples with installation instructions.
  • Grouped annotations: Related annotations that work together are grouped in a single expandable row, showing how they map to a unified configuration.
  • F5 NGINX Ingress Controller-only rows: Rows marked No direct equivalent on the left are features unique to the F5 NGINX Ingress Controller with no community equivalent.

Access Control

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/denylist-source-range: "192.168.1.100"
  nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,172.16.0.0/12"
F5 NGINX Ingress Controller
# 1. Create the AccessControl Policy
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: access-control
spec:
  accessControl:
    allow:  # whitelist-source-range
      - 10.0.0.0/8
      - 172.16.0.0/12
    deny:  # denylist-source-range
      - 192.168.1.100
---
# 2. Reference from Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.org/policies: "access-control"
# ... rest of Ingress spec
New in v5.4.0: AccessControl policies can now be referenced directly from Ingress resources using the nginx.org/policies annotation. This is the simplest migration path — you stay on Ingress resources.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/denylist-source-range: "192.168.1.100"
  nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,172.16.0.0/12"
F5 NGINX Ingress Controller
# 1. Create the AccessControl Policy
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: access-control
spec:
  accessControl:
    allow:  # whitelist-source-range
      - 10.0.0.0/8
      - 172.16.0.0/12
    deny:  # denylist-source-range
      - 192.168.1.100
---
# 2. Reference from VirtualServer
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  policies:
    - name: access-control
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      action:
        pass: backend
Note: The VirtualServer approach has been available since before v5.4.0. Use this if you are already migrating to VirtualServer resources for other reasons (e.g., advanced routing, traffic splitting).
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/satisfy: "any"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # satisfy
    satisfy any;  # satisfy
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/satisfy: "any"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # satisfy
        satisfy any;
      action:
        pass: backend

Authentication (Basic)

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-realm: "Protected Area"
  nginx.ingress.kubernetes.io/auth-secret: "basic-auth"
  nginx.ingress.kubernetes.io/auth-secret-type: "auth-file"
  nginx.ingress.kubernetes.io/auth-type: "basic"
F5 NGINX Ingress Controller
# auth-secret-type → Secret type
apiVersion: v1
kind: Secret
metadata:
  name: basic-auth
type: nginx.org/htpasswd  # auth-secret-type
data:
  htpasswd: dXNlcjokYXByMS4uLg==
---
annotations:
  nginx.org/basic-auth-realm: "Protected Area"  # auth-realm
  nginx.org/basic-auth-secret: "basic-auth"  # auth-secret
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-realm: "Protected Area"
  nginx.ingress.kubernetes.io/auth-secret: "basic-auth"
  nginx.ingress.kubernetes.io/auth-secret-type: "auth-file"
  nginx.ingress.kubernetes.io/auth-type: "basic"
F5 NGINX Ingress Controller
apiVersion: v1
kind: Secret
metadata:
  name: basic-auth
type: nginx.org/htpasswd
data:
  htpasswd: dXNlcjokYXByMS4uLg==
---
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: basic-auth-policy
spec:
  basicAuth:
    realm: "Protected Area"  # auth-realm
    secret: basic-auth  # auth-secret
Note: The community auth-secret-type annotation (auth-file or auth-map) has no F5 NGINX Ingress Controller equivalent. The F5 NGINX Ingress Controller only supports htpasswd format, specified via the Secret's type: nginx.org/htpasswd field. The auth-type annotation is also implicit — the F5 NGINX Ingress Controller only supports basic auth via these annotations.

Buffering

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/client-body-buffer-size: "16k"
F5 NGINX Ingress Controller
annotations:
  nginx.org/client-body-buffer-size: "16k"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/client-body-buffer-size: "16k"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      client-body-buffer-size: "16k"  # client-body-buffer-size
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-body-size: "10m"
F5 NGINX Ingress Controller
annotations:
  nginx.org/client-max-body-size: "10m"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-body-size: "10m"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      client-max-body-size: "10m"  # proxy-body-size
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-buffer-size: "8k"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      buffer-size: "8k"  # proxy-buffer-size
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-buffering: "on"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-buffering: "on"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-buffering: "on"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      buffering: true  # proxy-buffering
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-buffers: "4 8k"
Note: The F5 NGINX Ingress Controller annotation uses a combined format: "number size" (e.g., "4 8k").
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      buffers:  # proxy-buffers-number
        number: 4
        size: "8k"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-busy-buffers-size: "16k"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-busy-buffers-size: "16k"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-busy-buffers-size: "16k"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      busy-buffers-size: "16k"  # proxy-busy-buffers-size
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-max-temp-file-size: "1024m"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-max-temp-file-size: "1024m"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # proxy-request-buffering
    proxy_request_buffering off;  # proxy-request-buffering
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # proxy-request-buffering
        proxy_request_buffering off;
      action:
        pass: backend
Note: The F5 NGINX Ingress Controller does not have a dedicated proxy-request-buffering annotation or ConfigMap key. Use location-snippets to set the proxy_request_buffering directive.

Canary / Traffic Splitting

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# Canary Ingress
annotations:
  nginx.ingress.kubernetes.io/canary: "true"
  nginx.ingress.kubernetes.io/canary-by-cookie: "canary"
  nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
  nginx.ingress.kubernetes.io/canary-by-header-pattern: "^(test|staging)$"
  nginx.ingress.kubernetes.io/canary-by-header-value: "always"
  nginx.ingress.kubernetes.io/canary-weight: "20"
  nginx.ingress.kubernetes.io/canary-weight-total: "100"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: main
      service: main-svc
      port: 80
    - name: canary
      service: canary-svc
      port: 80
  routes:
    - path: /
      matches:
        - conditions:
            - header: X-Canary  # canary-by-header
              value: always  # canary-by-header-value
          action:
            pass: canary
        - conditions:
            - header: X-Canary  # canary-by-header
              value: "~^(test|staging)$"  # canary-by-header-pattern (regex)
          action:
            pass: canary
        - conditions:
            - cookie: canary  # canary-by-cookie
              value: "true"
          action:
            pass: canary
      splits:  # canary-weight / canary-weight-total
        - weight: 80
          action: { pass: main }
        - weight: 20
          action: { pass: canary }

Configuration Snippets

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/configuration-snippet: |
    add_header X-Custom "value";
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # configuration-snippet
    add_header X-Custom "value";
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/configuration-snippet: |
    add_header X-Custom "value";
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # configuration-snippet
        add_header X-Custom "value";
      action:
        pass: backend
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/server-snippet: |
    location /health { return 200; }
F5 NGINX Ingress Controller
annotations:
  nginx.org/server-snippets: |  # server-snippet
    location /health { return 200; }
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/server-snippet: |
    location /health { return 200; }
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  server-snippets: |  # server-snippet
    location /health { return 200; }
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      action:
        pass: backend
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/stream-snippet: |
    server { listen 3306; proxy_pass mysql; }
F5 NGINX Ingress Controller
# stream-snippet → GlobalConfiguration + TransportServer CRD
apiVersion: k8s.nginx.org/v1
kind: GlobalConfiguration
metadata:
  name: nginx-configuration
  namespace: nginx-ingress
spec:
  listeners:
    - name: mysql-tcp
      port: 3306  # from stream-snippet listen directive
      protocol: TCP
---
apiVersion: k8s.nginx.org/v1
kind: TransportServer
metadata:
  name: mysql-tcp
spec:
  listener:
    name: mysql-tcp  # references GlobalConfiguration listener
    protocol: TCP
  upstreams:
    - name: mysql
      service: mysql  # from stream-snippet proxy_pass
      port: 3306
  action:
    pass: mysql

CORS / Header Manipulation

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
  nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type"
  nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
  nginx.ingress.kubernetes.io/cors-allow-origin: "https://frontend.example.com"
  nginx.ingress.kubernetes.io/cors-expose-headers: "X-Request-ID, X-Custom-Header"
  nginx.ingress.kubernetes.io/cors-max-age: "86400"
  nginx.ingress.kubernetes.io/enable-cors: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/server-snippets: |  # enable-cors + cors-*
    set $cors_origin "";
    if ($http_origin ~* "^https://frontend\.example\.com$") {
        set $cors_origin $http_origin;
    }
    add_header Access-Control-Allow-Origin $cors_origin always;  # cors-allow-origin
    add_header Access-Control-Allow-Credentials "true" always;  # cors-allow-credentials
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;  # cors-allow-methods
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;  # cors-allow-headers
    add_header Access-Control-Expose-Headers "X-Request-ID, X-Custom-Header" always;  # cors-expose-headers
    add_header Access-Control-Max-Age 86400 always;  # cors-max-age
    if ($request_method = OPTIONS) {  # enable-cors
        return 204;
    }
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/enable-cors: "true"
  nginx.ingress.kubernetes.io/cors-allow-origin: "https://frontend.example.com"
  nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
  nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type"
  nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
  nginx.ingress.kubernetes.io/cors-expose-headers: "X-Request-ID"
  nginx.ingress.kubernetes.io/cors-max-age: "3600"
F5 NGINX Ingress Controller — Policy CRD
# 1. Create the CORS Policy
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: cors-policy
spec:
  cors:
    allowOrigin:  # cors-allow-origin
      - "https://frontend.example.com"
    allowMethods:  # cors-allow-methods
      - "GET"
      - "POST"
      - "PUT"
      - "DELETE"
      - "OPTIONS"
    allowHeaders:  # cors-allow-headers
      - "Authorization"
      - "Content-Type"
    allowCredentials: true  # cors-allow-credentials
    exposeHeaders:  # cors-expose-headers
      - "X-Request-ID"
    maxAge: 3600  # cors-max-age
---
# 2. Reference from Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.org/policies: "cors-policy"
# ... rest of Ingress spec

# Or reference from VirtualServer:
# spec:
#   policies:
#     - name: cors-policy
New in v5.4.0: The CORS Policy CRD is the recommended migration path. Create a reusable Policy and reference it via nginx.org/policies on Ingress or VirtualServer.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
  nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type"
  nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
  nginx.ingress.kubernetes.io/cors-allow-origin: "https://frontend.example.com"
  nginx.ingress.kubernetes.io/cors-expose-headers: "X-Request-ID, X-Custom-Header"
  nginx.ingress.kubernetes.io/cors-max-age: "86400"
  nginx.ingress.kubernetes.io/enable-cors: "true"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: cors-app
spec:
  host: api.example.com
  upstreams:
    - name: api-backend
      service: api-service
      port: 80
  routes:
    - path: /
      action:
        proxy:
          upstream: api-backend
          responseHeaders:  # declarative header manipulation
            add:
              - always: true
                name: Access-Control-Allow-Origin  # cors-allow-origin
                value: "https://frontend.example.com"
              - always: true
                name: Access-Control-Allow-Credentials  # cors-allow-credentials
                value: "true"
              - always: true
                name: Access-Control-Allow-Methods  # cors-allow-methods
                value: "GET, POST, PUT, DELETE, OPTIONS"
              - always: true
                name: Access-Control-Allow-Headers  # cors-allow-headers
                value: "Authorization, Content-Type"
              - always: true
                name: Access-Control-Expose-Headers  # cors-expose-headers
                value: "X-Request-ID, X-Custom-Header"
              - always: true
                name: Access-Control-Max-Age  # cors-max-age
                value: "86400"
Recommended: The responseHeaders approach provides a fully declarative way to manage CORS and other response headers without raw NGINX snippets. Headers are set per-route via action.proxy.responseHeaders, and the always flag ensures headers are added regardless of response status code. See the VirtualServer CRD docs for additional options like hide, ignore, and pass.

Deprecated

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/http2-push-preload: "true"
F5 NGINX Ingress Controller
# Not supported — HTTP/2 Server Push was deprecated
# by major browsers and removed from NGINX 1.25.1.
# No migration action needed.
Note: HTTP/2 Server Push (http2_push_preload) was removed from NGINX in version 1.25.1 after major browsers deprecated the feature. This annotation can be safely removed during migration.

Error Handling

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/custom-http-errors: "404,500,502"
  nginx.ingress.kubernetes.io/default-backend: "error-svc"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
    - name: error-backend  # default-backend
      service: error-svc
      port: 80
  routes:
    - path: /
      action:
        pass: backend
      errorPages:  # custom-http-errors
        - codes: [404, 500, 502]
          pass: error-backend

Headers

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # connection-proxy-header
    proxy_set_header Connection "keep-alive";  # connection-proxy-header
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  routes:
    - path: /
      action:
        proxy:
          upstream: my-backend
          requestHeaders:  # connection-proxy-header
            set:
              - name: Connection
                value: "keep-alive"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/custom-headers: "default/custom-headers-configmap"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  routes:
    - path: /
      action:
        proxy:
          upstream: my-backend
          responseHeaders:  # custom-headers
            add:
              - name: X-Frame-Options
                value: "DENY"
              - name: X-Content-Type-Options
                value: "nosniff"
Kubernetes Ingress NGINX (Ingress-NGINX)
# ConfigMap setting only
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  server-tokens: "false"
F5 NGINX Ingress Controller
annotations:
  nginx.org/server-tokens: "false"
Note: The Community controller configures server tokens via ConfigMap only. The F5 NGINX Ingress Controller provides a per-Ingress annotation.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/upstream-vhost: "backend.internal"
  nginx.ingress.kubernetes.io/x-forwarded-prefix: "/api"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  routes:
    - path: /api
      action:
        proxy:
          upstream: my-backend
          requestHeaders:
            set:
              - name: Host
                value: "backend.internal"  # upstream-vhost
              - name: X-Forwarded-Prefix
                value: "/api"  # x-forwarded-prefix
Kubernetes Ingress NGINX (Ingress-NGINX)
# Custom headers set via ConfigMap
# proxy-set-headers in controller ConfigMap
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-set-headers: "my-custom-headers"
---
# ConfigMap with custom headers
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-custom-headers
data:
  X-Custom-Header: "my-value"
  X-Forwarded-Proto: "$scheme"
Note: nginx.org/proxy-set-headers requires two resources: (1) the annotation on the Ingress, referencing a ConfigMap name, and (2) the ConfigMap itself containing header key-value pairs. Headers defined in the ConfigMap are added to all proxied requests for that Ingress. The ConfigMap must be in the same namespace as the Ingress resource.

HSTS

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# ConfigMap settings only
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  hsts: "true"
  hsts-max-age: "31536000"
  hsts-include-subdomains: "true"
  hsts-preload: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/hsts: "true"
  nginx.org/hsts-include-subdomains: "true"
  nginx.org/hsts-max-age: "31536000"
Note: HSTS annotations are F5 NGINX Ingress Controller-only and provide per-Ingress control. The community controller handles HSTS via ConfigMap only. The F5 NGINX Ingress Controller's nginx.org/hsts annotation includes the preload directive by default — there is no separate equivalent of the community hsts-preload ConfigMap key.
Kubernetes Ingress NGINX (Ingress-NGINX)
# No equivalent
# HSTS headers are always added regardless
# of proxy/load balancer presence
F5 NGINX Ingress Controller
annotations:
  nginx.org/hsts: "true"
  nginx.org/hsts-behind-proxy: "true"
Note: nginx.org/hsts-behind-proxy controls whether HSTS headers are added when NGINX sits behind a proxy or load balancer. When true, HSTS headers are added regardless of the connection protocol. This is an NIC-only feature with no community controller equivalent.

Ingress Configuration

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# No direct equivalent
# Canary/traffic-splitting uses separate
# canary annotations
F5 NGINX Ingress Controller
# Master Ingress (server-level config)
annotations:
  nginx.org/mergeable-ingress-type: "master"
---
# Minion Ingress (route-level config)
annotations:
  nginx.org/mergeable-ingress-type: "minion"
Note: Mergeable Ingress types allow splitting configuration across multiple Ingress resources for the same host. The master handles server-level settings while minion resources define individual routes.

Load Balancing

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/load-balance: "ewma"
F5 NGINX Ingress Controller
annotations:
  nginx.org/lb-method: "least_conn"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/load-balance: "ewma"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      lb-method: "least_conn"  # load-balance
Note: Supported methods differ. The F5 NGINX Ingress Controller supports: round_robin, least_conn, ip_hash, hash, random, random two, and random two least_conn (NGINX Plus adds least_time variants). The community controller's ewma method is not supported — the closest equivalent is least_conn. The F5 NGINX Ingress Controller's default is random two least_conn (not round_robin), so load balancing behavior may change even without explicit configuration.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/service-upstream: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/use-cluster-ip: "true"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/service-upstream: "true"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      use-cluster-ip: true  # service-upstream
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"
F5 NGINX Ingress Controller
annotations:
  nginx.org/lb-method: "hash $request_uri consistent"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"
  nginx.ingress.kubernetes.io/upstream-hash-by-subset: "true"
  nginx.ingress.kubernetes.io/upstream-hash-by-subset-size: "3"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      lb-method: "hash $request_uri consistent"  # upstream-hash-by
Note: The F5 NGINX Ingress Controller has no dedicated upstream-hash-by equivalent. Instead, the hash key is specified as part of the lb-method value (e.g., hash $request_uri consistent). Subset hashing (upstream-hash-by-subset) is not supported; use consistent hashing for similar distribution.

Logging

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/enable-access-log: "false"
F5 NGINX Ingress Controller
# Set via ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  access-log-off: "true"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # enable-rewrite-log
    rewrite_log on;  # enable-rewrite-log
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # enable-rewrite-log
        rewrite_log on;  # enable-rewrite-log
      action:
        pass: backend
Note: The F5 NGINX Ingress Controller does not have a dedicated rewrite-log ConfigMap key. Use location-snippets to enable the rewrite_log directive. Rewrite logging outputs to the error log at notice level.

Request Mirroring

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/mirror-host: "mirror.example.com"
  nginx.ingress.kubernetes.io/mirror-request-body: "on"
  nginx.ingress.kubernetes.io/mirror-target: "https://mirror.example.com$request_uri"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # mirror-target + mirror-request-body
    mirror /mirror;  # mirror-target
    mirror_request_body on;  # mirror-request-body
  nginx.org/server-snippets: |  # mirror-host + mirror-target
    location /mirror {
      internal;
      proxy_set_header Host mirror.example.com;  # mirror-host
      proxy_pass https://mirror.example.com$request_uri;  # mirror-target
    }
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/mirror-host: "mirror.example.com"
  nginx.ingress.kubernetes.io/mirror-request-body: "on"
  nginx.ingress.kubernetes.io/mirror-target: "https://mirror.example.com$request_uri"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  server-snippets: |  # mirror-host + mirror-target
    location /mirror {
      internal;
      proxy_set_header Host mirror.example.com;  # mirror-host
      proxy_pass https://mirror.example.com$request_uri;  # mirror-target
    }
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # mirror-target + mirror-request-body
        mirror /mirror;  # mirror-target
        mirror_request_body on;  # mirror-request-body
      action:
        pass: backend

mTLS (Client Certificate Verification)

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-tls-error-page: "https://example.com/cert-error"
  nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
  nginx.ingress.kubernetes.io/auth-tls-secret: "ns/ca-secret"
  nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
  nginx.ingress.kubernetes.io/auth-tls-verify-depth: "2"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: ingress-mtls
spec:
  ingressMTLS:
    clientCertSecret: ca-secret  # auth-tls-secret
    verifyClient: "on"  # auth-tls-verify-client
    verifyDepth: 2  # auth-tls-verify-depth
---
# auth-tls-pass-certificate-to-upstream → location-snippets
# auth-tls-error-page → server-snippets
annotations:
  nginx.org/location-snippets: |  # auth-tls-pass-certificate-to-upstream
    proxy_set_header ssl-client-cert $ssl_client_escaped_cert;  # auth-tls-pass-certificate-to-upstream
  nginx.org/server-snippets: |  # auth-tls-error-page
    error_page 495 496 = https://example.com/cert-error;  # auth-tls-error-page
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-tls-match-cn: "CN=client-[0-9]+"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # auth-tls-match-cn
    if ($ssl_client_s_dn !~ "CN=client-[0-9]+") {  # auth-tls-match-cn
        return 403;
    }
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-tls-match-cn: "CN=client-[0-9]+"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # auth-tls-match-cn
        if ($ssl_client_s_dn !~ "CN=client-[0-9]+") {
            return 403;
        }
      action:
        pass: backend
Note: The F5 NGINX Ingress Controller's ingressMTLS Policy does not have a built-in CN matching feature. Use location-snippets to add custom CN validation logic.

mTLS (Backend/Egress)

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-ssl-ciphers: "HIGH:!aNULL:!MD5"
  nginx.ingress.kubernetes.io/proxy-ssl-name: "backend.example.com"
  nginx.ingress.kubernetes.io/proxy-ssl-protocols: "TLSv1.2 TLSv1.3"
  nginx.ingress.kubernetes.io/proxy-ssl-secret: "ns/client-cert"
  nginx.ingress.kubernetes.io/proxy-ssl-server-name: "on"
  nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
  nginx.ingress.kubernetes.io/proxy-ssl-verify-depth: "2"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: egress-mtls
spec:
  egressMTLS:
    ciphers: "HIGH:!aNULL:!MD5"  # proxy-ssl-ciphers
    sslName: "backend.example.com"  # proxy-ssl-name
    protocols: "TLSv1.2 TLSv1.3"  # proxy-ssl-protocols
    tlsSecret: client-cert  # proxy-ssl-secret
    serverName: true  # proxy-ssl-server-name
    verifyServer: true  # proxy-ssl-verify
    verifyDepth: 2  # proxy-ssl-verify-depth
    trustedCertSecret: ca-cert

ModSecurity / WAF

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/enable-modsecurity: "true"
  nginx.ingress.kubernetes.io/enable-owasp-core-rules: "true"
  nginx.ingress.kubernetes.io/modsecurity-snippet: |
    SecRuleEngine On
    SecRule ARGS "@contains <script>" "id:1,deny,status:403"
  nginx.ingress.kubernetes.io/modsecurity-transaction-id: "$request_id"
F5 NGINX Ingress Controller
# No direct OSS replacement
# For WAF capabilities, see the Plus WAF section
# which uses the F5 WAF for NGINX (App Protect)
No OSS Equivalent: The F5 NGINX Ingress Controller does not include ModSecurity or any built-in WAF module. For WAF capabilities, F5 WAF for NGINX is available with NGINX Plus — see the WAF section in Plus Mappings for migration examples.
Note: The community controller's ModSecurity support relies on a third-party module compiled into the controller image — it is not a native Kubernetes-integrated WAF solution. Neither controller provides an open-source WAF alternative.

OpenTelemetry

Key difference: The community controller supports per-Ingress OpenTelemetry control via annotations (enable-opentelemetry, opentelemetry-trust-incoming-span). The F5 NGINX Ingress Controller configures OpenTelemetry globally via ConfigMap — tracing applies to all routes when enabled. Per-Ingress toggling is not supported.
Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/enable-opentelemetry: "true"
F5 NGINX Ingress Controller
# Global ConfigMap configuration (applies to all routes)
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  otel-trace-in-http: "true"  # enable-opentelemetry
  otel-exporter-endpoint: "otel-collector:4317"  # required: collector address
  otel-service-name: "nginx-ingress"  # optional: service name for traces
Note: otel-trace-in-http is the direct replacement for enable-opentelemetry. Additional ConfigMap keys: otel-exporter-endpoint (required), otel-service-name, otel-exporter-header-name, otel-exporter-header-value. Unlike the community annotation, this enables tracing globally — not per-Ingress.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span: "true"
F5 NGINX Ingress Controller
# No per-Ingress equivalent.
# The F5 NGINX Ingress Controller always trusts
# incoming trace context when tracing is enabled.
# To enable tracing globally:
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  otel-trace-in-http: "true"
  otel-exporter-endpoint: "otel-collector:4317"
Note: The community controller's opentelemetry-trust-incoming-span enables per-Ingress control over whether to trust incoming trace context (W3C Trace Context propagation). The F5 NGINX Ingress Controller does not have a per-Ingress equivalent — when tracing is enabled via ConfigMap, incoming trace context is always propagated. This annotation can be safely removed during migration.
Kubernetes Ingress NGINX (Ingress-NGINX)
# No equivalent ConfigMap keys
# The community controller configures the
# OTel collector via its own internal config
F5 NGINX Ingress Controller
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  otel-exporter-endpoint: "otel-collector:4317"  # required: collector address
  otel-exporter-header-name: "Authorization"  # optional: auth header name
  otel-exporter-header-value: "Bearer token"  # optional: auth header value
  otel-service-name: "my-app"  # optional: service name for traces
Note: These ConfigMap keys are NIC-only and configure the OpenTelemetry exporter. otel-exporter-endpoint is required when tracing is enabled. otel-service-name sets the service name in traces (defaults to nginx-ingress). otel-exporter-header-name and otel-exporter-header-value add custom headers to exporter requests (e.g., for authentication).

Passive Health Checks

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# ConfigMap keys (global):
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  upstream-fail-timeout: "30s"
  upstream-max-fails: "3"
F5 NGINX Ingress Controller
# Per-Ingress annotations:
annotations:
  nginx.org/fail-timeout: "30s"  # upstream-fail-timeout
  nginx.org/max-fails: "3"  # upstream-max-fails
Note: The community controller configures passive health checks globally via ConfigMap keys. The F5 NGINX Ingress Controller uses per-Ingress annotations (nginx.org/max-fails, nginx.org/fail-timeout), giving you finer-grained control. The proxy-next-upstream annotations (see Proxy Settings) complement passive health checks by controlling retry behavior when an upstream fails.
Kubernetes Ingress NGINX (Ingress-NGINX)
# ConfigMap keys (global):
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  upstream-fail-timeout: "30s"
  upstream-max-fails: "3"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      fail-timeout: 30s  # upstream-fail-timeout
      max-fails: 3  # upstream-max-fails
Note: The VirtualServer CRD allows passive health check settings per upstream. For active health checks that proactively probe endpoints, see Active Health Checks in Plus Mappings.

Proxy Settings

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-next-upstream: "error timeout"
  nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "30"
  nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "3"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-next-upstream: "error timeout"
  nginx.org/proxy-next-upstream-timeout: "30s"
  nginx.org/proxy-next-upstream-tries: "3"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-next-upstream: "error timeout"
  nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "30"
  nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "3"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      next-upstream: "error timeout"  # proxy-next-upstream
      next-upstream-timeout: 30s  # proxy-next-upstream-timeout
      next-upstream-tries: 3  # proxy-next-upstream-tries
New in v5.4.0: The nginx.org/proxy-next-upstream, nginx.org/proxy-next-upstream-timeout, and nginx.org/proxy-next-upstream-tries annotations are new. They provide direct 1:1 mappings from the community annotations without requiring a VirtualServer CRD.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # proxy-http-version
    proxy_http_version 1.1;  # proxy-http-version
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # proxy-http-version
        proxy_http_version 1.1;  # proxy-http-version
      action:
        pass: backend
Note: The F5 NGINX Ingress Controller does not have a dedicated annotation for HTTP version. Use location-snippets to set proxy_http_version directly.

Rate Limiting

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
  nginx.ingress.kubernetes.io/limit-connections: "5"
  nginx.ingress.kubernetes.io/limit-rate: "100k"
  nginx.ingress.kubernetes.io/limit-rate-after: "1m"
  nginx.ingress.kubernetes.io/limit-rpm: "300"
  nginx.ingress.kubernetes.io/limit-rps: "10"
  nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8,172.16.0.0/12"
F5 NGINX Ingress Controller
annotations:
  nginx.org/limit-req-burst: "50"  # limit-burst-multiplier (limit-rps × multiplier)
  nginx.org/limit-req-rate: "10r/s"  # limit-rps (also covers limit-rpm)
  # limit-connections, limit-rate, limit-rate-after, limit-whitelist
  # → use location-snippets:
  nginx.org/location-snippets: |  # limit-connections / limit-rate / limit-rate-after
    limit_conn addr 5;  # limit-connections
    limit_rate 100k;  # limit-rate
    limit_rate_after 1m;  # limit-rate-after
    # limit-whitelist → use geo module or map in server-snippets
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
  nginx.ingress.kubernetes.io/limit-connections: "5"
  nginx.ingress.kubernetes.io/limit-rate: "100k"
  nginx.ingress.kubernetes.io/limit-rate-after: "1m"
  nginx.ingress.kubernetes.io/limit-rpm: "300"
  nginx.ingress.kubernetes.io/limit-rps: "10"
  nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8,172.16.0.0/12"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: rate-limit
spec:
  rateLimit:
    burst: 50  # limit-rps × limit-burst-multiplier
    key: ${binary_remote_addr}
    rate: 10r/s  # limit-rps
    rejectCode: 429
    zoneSize: 10M
Note: The rateLimit Policy CRD covers limit-rps and limit-burst-multiplier. The community annotations limit-connections, limit-rate, limit-rate-after, limit-rpm, and limit-whitelist have no Policy CRD equivalents — use location-snippets for those (see the Annotation Approach).
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  limit-req-status-code: "429"
F5 NGINX Ingress Controller
annotations:
  nginx.org/limit-req-reject-code: "429"
Note: The community controller sets the rate limit rejection status code globally via ConfigMap. The F5 NGINX Ingress Controller sets it per-Ingress via the nginx.org/limit-req-reject-code annotation (default: 429).
Kubernetes Ingress NGINX (Ingress-NGINX)
# No equivalents for these fine-grained
# rate limiting controls
F5 NGINX Ingress Controller
annotations:
  nginx.org/limit-req-rate: "10r/s"
  nginx.org/limit-req-burst: "50"
  nginx.org/limit-req-key: "${binary_remote_addr}"
  nginx.org/limit-req-delay: "5"
  nginx.org/limit-req-no-delay: "true"
  nginx.org/limit-req-zone-size: "10M"
  nginx.org/limit-req-reject-code: "429"
  nginx.org/limit-req-log-level: "warn"
  nginx.org/limit-req-dry-run: "false"
  nginx.org/limit-req-scale: "true"
Note: These NIC-only annotations provide fine-grained rate limiting control. limit-req-key customizes the rate limiting key (default: ${binary_remote_addr}). limit-req-scale divides the rate by pod count for consistency during autoscaling. limit-req-reject-code sets the response code for rejected requests (default: 429). limit-req-dry-run enables logging without enforcing limits.

Redirects

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/permanent-redirect: "https://new.example.com"
  nginx.ingress.kubernetes.io/permanent-redirect-code: "308"
  # Or for temporary redirects:
  # nginx.ingress.kubernetes.io/temporal-redirect: "https://maintenance.example.com"
  # nginx.ingress.kubernetes.io/temporal-redirect-code: "307"
  # Or for www redirect:
  # nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  host: old.example.com
  routes:
    - path: /
      action:
        redirect:
          url: https://new.example.com${request_uri}  # permanent-redirect
          code: 308  # permanent-redirect-code
  # temporal-redirect + temporal-redirect-code:
  # - path: /maintenance
  #   action:
  #     redirect:
  #       url: https://maintenance.example.com
  #       code: 307
  # from-to-www-redirect → separate VirtualServer:
  # server-snippets: |
  #   return 301 https://www.example.com$request_uri;

Rewrites

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/app-root: "/dashboard"
  nginx.ingress.kubernetes.io/rewrite-target: /$2
  nginx.ingress.kubernetes.io/use-regex: "true"
# Used with Ingress path: /api(/|$)(.*)
F5 NGINX Ingress Controller
annotations:
  nginx.org/app-root: "/dashboard"
  nginx.org/path-regex: "case_sensitive"
  nginx.org/rewrite-target: /$2
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/app-root: "/dashboard"
  nginx.ingress.kubernetes.io/rewrite-target: /$2
  nginx.ingress.kubernetes.io/use-regex: "true"
# Used with Ingress path: /api(/|$)(.*)
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  routes:
    - path: /
      action:
        redirect:
          url: /dashboard  # app-root
          code: 302
    - path: ~ ^/api(/|$)(.*)  # use-regex
      action:
        proxy:
          upstream: api
          rewritePath: /$2  # rewrite-target
New in v5.4.0: The nginx.org/app-root annotation is new. It provides a direct 1:1 mapping from the community app-root annotation without requiring a VirtualServer CRD.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-cookie-domain: "internal.example.com external.example.com"
  nginx.ingress.kubernetes.io/proxy-cookie-path: "/internal/ /external/"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # proxy-cookie-domain / proxy-cookie-path
    proxy_cookie_domain internal.example.com external.example.com;  # proxy-cookie-domain
    proxy_cookie_path /internal/ /external/;  # proxy-cookie-path
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-cookie-domain: "internal.example.com external.example.com"
  nginx.ingress.kubernetes.io/proxy-cookie-path: "/internal/ /external/"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # proxy-cookie-domain / proxy-cookie-path
        proxy_cookie_domain internal.example.com external.example.com;
        proxy_cookie_path /internal/ /external/;
      action:
        pass: backend
Note: The F5 NGINX Ingress Controller does not have dedicated annotations for proxy cookie rewriting. Use location-snippets to configure proxy_cookie_domain and proxy_cookie_path directives.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-redirect-from: "http://internal/"
  nginx.ingress.kubernetes.io/proxy-redirect-to: "https://external/"
F5 NGINX Ingress Controller
annotations:
  nginx.org/server-snippets: |  # proxy-redirect-from / proxy-redirect-to
    proxy_redirect http://internal/ https://external/;  # proxy-redirect-from / proxy-redirect-to
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-redirect-from: "http://internal/"
  nginx.ingress.kubernetes.io/proxy-redirect-to: "https://external/"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  server-snippets: |  # proxy-redirect-from / proxy-redirect-to
    proxy_redirect http://internal/ https://external/;
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      action:
        pass: backend
Note: The F5 NGINX Ingress Controller also supports a proxy-redirect ConfigMap key for global proxy redirect behavior. Use server-snippets for per-Ingress control.
Kubernetes Ingress NGINX (Ingress-NGINX)
# No per-service rewrite equivalent
# rewrite-target applies globally to all
# backends in the Ingress resource
F5 NGINX Ingress Controller
annotations:
  nginx.org/rewrites: "serviceName=tea-svc rewrite=/;serviceName=coffee-svc rewrite=/beans"
Note: nginx.org/rewrites enables per-service URL rewriting within a single Ingress resource. Each semicolon-separated entry specifies a service name and its rewrite path. This is an NIC-only feature with no community controller equivalent.

Route Delegation

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/server-alias: "alias.example.com"
F5 NGINX Ingress Controller
annotations:
  nginx.org/server-snippets: |  # server-alias
    server_name alias.example.com;  # server-alias
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/server-alias: "alias.example.com"
F5 NGINX Ingress Controller
# server-alias → separate VirtualServer per host
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: alias-app
spec:
  host: alias.example.com  # server-alias
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      action:
        pass: backend
Note: The community server-alias annotation adds an additional hostname to the same NGINX server block. The F5 NGINX Ingress Controller does not have an equivalent annotation — instead, create a separate VirtualServer resource for each hostname, all pointing to the same backend service. Alternatively, use nginx.org/server-snippets to add additional server_name directives.
Tip: This feature requires CRDs. See Installing CRDs for Helm and manifest installation instructions.
Note: The community controller has no equivalent for cross-namespace route delegation. VirtualServerRoute allows different teams to manage their own routing rules while a central VirtualServer controls the domain.
Kubernetes Ingress NGINX (Ingress-NGINX)
# No equivalent — each team must have
# their own Ingress resource per host,
# or share a single Ingress manifest
F5 NGINX Ingress Controller
# VirtualServer (platform team)
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: main-app
  namespace: platform
spec:
  host: app.example.com
  routes:
    - path: /api
      route: api-team/api-routes
    - path: /web
      route: web-team/web-routes
---
# VirtualServerRoute (API team)
apiVersion: k8s.nginx.org/v1
kind: VirtualServerRoute
metadata:
  name: api-routes
  namespace: api-team
spec:
  host: app.example.com
  upstreams:
    - name: api-v1
      service: api-v1-service
      port: 80
  subroutes:
    - path: /api/v1
      action:
        pass: api-v1

SSL/TLS

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
F5 NGINX Ingress Controller
annotations:
  nginx.org/ssl-services: "my-service"
Note: For gRPC backends, use nginx.org/grpc-services: "my-service" instead.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 443
      tls:
        enable: true  # backend-protocol
Note: For gRPC backends, use type: grpc on the upstream instead. For gRPC over TLS, combine both: type: grpc and tls.enable: true.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/redirect-to-https: "true"
Note: force-ssl-redirect in the Community controller forces HTTPS redirect even without a TLS certificate. Use nginx.org/redirect-to-https for similar behavior.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/preserve-trailing-slash: "true"
  nginx.ingress.kubernetes.io/ssl-redirect: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/redirect-to-https: "true"
  # Trailing slash is preserved by default in redirects
Note: This annotation affects SSL redirect behavior in the Community controller. The F5 NGINX Ingress Controller preserves trailing slashes by default in its redirect logic.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/ssl-ciphers: "HIGH:!aNULL:!MD5"
F5 NGINX Ingress Controller
annotations:
  nginx.org/ssl-ciphers: "HIGH:!aNULL:!MD5"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/ssl-passthrough: "true"
F5 NGINX Ingress Controller
# ssl-passthrough → TransportServer with built-in tls-passthrough listener
apiVersion: k8s.nginx.org/v1
kind: TransportServer
metadata:
  name: ssl-passthrough-app
spec:
  listener:
    name: tls-passthrough  # ssl-passthrough
    protocol: TLS_PASSTHROUGH
  host: secure.example.com
  upstreams:
    - name: backend
      service: secure-svc
      port: 443
  action:
    pass: backend
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers: "true"
F5 NGINX Ingress Controller
annotations:
  nginx.org/ssl-prefer-server-ciphers: "true"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/ssl-redirect: "true"
F5 NGINX Ingress Controller
annotations:
  # Match the community controller's 308 default
  # (preserves request method and body)
  nginx.org/http-redirect-code: "308"
  # Option 1: For TLS terminated at load balancer
  nginx.org/redirect-to-https: "true"
  # OR Option 2: For unconditional redirect
  nginx.org/ssl-redirect: "true"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/ssl-redirect: "true"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  host: app.example.com
  tls:
    secret: app-tls
    redirect:
      enable: true
      code: 308  # ssl-redirect (matches community 308 default)
  upstreams:
    - name: backend
      service: my-service
      port: 80
  routes:
    - path: /
      action:
        pass: backend
Important distinction:
  • nginx.org/redirect-to-https checks the X-Forwarded-Proto header before redirecting. Use this when TLS terminates at a load balancer in front of NGINX.
  • nginx.org/ssl-redirect performs an unconditional redirect for all incoming HTTP traffic. Use this when NGINX handles TLS termination directly. Default: true.
Note: The community controller's ssl-redirect defaults to a 308 Permanent Redirect, which preserves the original request method and body. The F5 NGINX Ingress Controller defaults to 301, which clients may downgrade to GET and drop the request body. To match the community behavior exactly, set nginx.org/http-redirect-code: "308" on the Ingress, or tls.redirect.code: 308 on the VirtualServer.
New in v5.4.0: The nginx.org/ssl-redirect and nginx.org/http-redirect-code annotations are new. Previously, only nginx.org/redirect-to-https was available, with a fixed 301 response code. Use ssl-redirect as the direct 1:1 mapping from the community annotation.
Kubernetes Ingress NGINX (Ingress-NGINX)
# No direct equivalent
# Redirect code is not configurable
# per Ingress resource
F5 NGINX Ingress Controller
annotations:
  nginx.org/http-redirect-code: "308"
  nginx.org/redirect-to-https: "true"
New in v5.4.0: Customizes the HTTP redirect status code used when redirecting to HTTPS (default: 301). Available as both a per-Ingress annotation and a global ConfigMap key (http-redirect-code). Common values: 301 (permanent), 302 (temporary), 307 (temporary, preserves method), 308 (permanent, preserves method).
Kubernetes Ingress NGINX (Ingress-NGINX)
# No direct equivalent
# Port configuration is handled at the
# controller/service level
F5 NGINX Ingress Controller
annotations:
  nginx.org/listen-ports: "8080,8443"
  nginx.org/listen-ports-ssl: "8443,9443"
Note: These annotations configure custom HTTP and HTTPS listen ports for the Ingress resource. Useful when the controller needs to listen on non-standard ports.

TCP/UDP Load Balancing

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# ConfigMap for TCP services
apiVersion: v1
kind: ConfigMap
metadata:
  name: tcp-services
data:
  3306: "default/mysql:3306"
F5 NGINX Ingress Controller
# tcp-services ConfigMap → GlobalConfiguration + TransportServer
apiVersion: k8s.nginx.org/v1
kind: GlobalConfiguration
spec:
  listeners:
    - name: mysql-tcp
      port: 3306  # "3306" key from tcp-services ConfigMap
      protocol: TCP
---
apiVersion: k8s.nginx.org/v1
kind: TransportServer
spec:
  listener:
    name: mysql-tcp
    protocol: TCP
  upstreams:
    - name: mysql
      service: mysql  # "default/mysql:3306" value from ConfigMap
      port: 3306
  action:
    pass: mysql

Timeouts

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-connect-timeout: "10s"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      connect-timeout: "10s"  # proxy-connect-timeout
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-read-timeout: "60s"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      read-timeout: "60s"  # proxy-read-timeout
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
F5 NGINX Ingress Controller
annotations:
  nginx.org/proxy-send-timeout: "60s"
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      send-timeout: "60s"  # proxy-send-timeout

Upstream Configuration

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# No per-Ingress upstream tuning
# Community controller uses ConfigMap defaults
F5 NGINX Ingress Controller
annotations:
  nginx.org/fail-timeout: "10s"
  nginx.org/keepalive: "32"
  nginx.org/max-conns: "100"
  nginx.org/max-fails: "3"
  nginx.org/upstream-zone-size: "256k"
Kubernetes Ingress NGINX (Ingress-NGINX)
# No per-Ingress upstream tuning
# Community controller uses ConfigMap defaults
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      fail-timeout: "10s"
      keepalive: 32
      max-conns: 100
      max-fails: 3
Note: These are F5 NGINX Ingress Controller-only features for fine-tuning upstream behavior. The community controller does not provide per-Ingress control over these settings.
Kubernetes Ingress NGINX (Ingress-NGINX)
# WebSocket support is automatic
# Just ensure proxy-http-version: "1.1"
# and proper Upgrade/Connection headers
F5 NGINX Ingress Controller
annotations:
  nginx.org/websocket-services: "ws-service"
Note: The Community controller handles WebSocket upgrades automatically. The F5 NGINX Ingress Controller provides an explicit annotation to enable WebSocket support for specific services.

Session Affinity / Sticky Sessions

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/affinity: "cookie"
  nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
  nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
  nginx.ingress.kubernetes.io/session-cookie-name: "SERVERID"
  nginx.ingress.kubernetes.io/session-cookie-path: "/"
F5 NGINX Ingress Controller
annotations:
  nginx.com/sticky-cookie-services: "serviceName=my-service srv_id expires=48h path=/"
Note: The nginx.com/sticky-cookie-services annotation provides a simpler way to configure session persistence via Ingress annotations. For more granular control (domain, secure, samesite, httpOnly), use the VirtualServer CRD approach.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/affinity: "cookie"
  nginx.ingress.kubernetes.io/affinity-mode: "balanced"
  nginx.ingress.kubernetes.io/session-cookie-change-on-failure: "true"
  nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none: "true"
  nginx.ingress.kubernetes.io/session-cookie-domain: ".example.com"
  nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
  nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
  nginx.ingress.kubernetes.io/session-cookie-name: "SERVERID"
  nginx.ingress.kubernetes.io/session-cookie-path: "/"
  nginx.ingress.kubernetes.io/session-cookie-samesite: "Strict"
  nginx.ingress.kubernetes.io/session-cookie-secure: "true"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      sessionCookie:
        domain: ".example.com"  # session-cookie-domain
        enable: true  # affinity: "cookie"
        expires: 48h  # session-cookie-expires / session-cookie-max-age
        httpOnly: true
        name: SERVERID  # session-cookie-name
        path: /  # session-cookie-path
        samesite: strict  # session-cookie-samesite
        secure: true  # session-cookie-secure
New in v5.4.0: Session persistence via sessionCookie is now available in both NGINX OSS and NGINX Plus. Community-specific features affinity-mode, session-cookie-change-on-failure, and session-cookie-conditional-samesite-none have no direct equivalents.
Kubernetes Ingress NGINX (Ingress-NGINX)
# Canary with session affinity behavior
annotations:
  nginx.ingress.kubernetes.io/affinity: "cookie"
  nginx.ingress.kubernetes.io/affinity-canary-behavior: "sticky"
  nginx.ingress.kubernetes.io/canary: "true"
  nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: main
      service: main-svc
      port: 80
      sessionCookie:  # affinity: "cookie" + affinity-canary-behavior: "sticky"
        enable: true  # affinity: "cookie"
        httpOnly: true
        name: SERVERID
    - name: canary
      service: canary-svc
      port: 80
      sessionCookie:  # affinity: "cookie" + affinity-canary-behavior: "sticky"
        enable: true  # affinity: "cookie"
        httpOnly: true
        name: SERVERID
  routes:
    - path: /
      matches:
        - conditions:
            - header: X-Canary  # canary-by-header
              value: "true"
          action:
            pass: canary  # canary: "true"
      action:
        pass: main
Note: The community controller's affinity-canary-behavior: "sticky" ensures users routed to canary by session affinity continue to be served by the canary. The F5 NGINX Ingress Controller separates these concerns: canary routing uses VirtualServer matches[], splits[], while session persistence uses the VirtualServer upstreams[].sessionCookie field. The sessionCookie feature is available in both NGINX OSS and NGINX Plus.

NGINX Plus Mappings

These features require an NGINX Plus subscription and provide enterprise-grade capabilities. Most Plus features use CRD-based configuration—click the expandable rows to see full examples. All items are annotations unless otherwise indicated with a badge. Community annotations use the nginx.ingress.kubernetes.io/ prefix; F5 NGINX Ingress Controller Plus annotations use the nginx.com/ prefix (or appprotect.f5.com/ for F5 WAF for NGINX).

How to Read the Mappings
  • Annotation-to-annotation rows : Direct mappings where you change the annotation name/prefix. Click to expand and see before/after Ingress YAML examples.
  • CRD-based rows : Annotations that map to a CRD (VirtualServer, Policy, or TransportServer). Click to expand for full CRD examples with installation instructions.
  • Grouped annotations: Related annotations that work together are grouped in a single expandable row, showing how they map to a unified configuration.
  • F5 NGINX Ingress Controller-only rows: Rows marked No direct equivalent on the left are features unique to the F5 NGINX Ingress Controller with no community equivalent.

API Key Authentication

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# No direct equivalent
# Requires custom Lua or external service
F5 NGINX Ingress Controller (Plus)
apiVersion: v1
kind: Secret
metadata:
  name: api-keys
type: nginx.org/apikey
data:
  client1: YXBpa2V5MTIzNDU=
---
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: api-key-auth
spec:
  apiKey:
    clientSecret: api-keys
    suppliedIn:
      header: [X-API-Key]
      query: [api_key]

Active Health Checks

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
annotations:
  nginx.com/health-checks: "true"
  nginx.com/health-checks-mandatory: "true"
  nginx.com/health-checks-mandatory-queue: "5"
  nginx.com/slow-start: "30s"
Note: Active health checks proactively probe upstream endpoints at configurable intervals, rather than waiting for client requests to fail. These require NGINX Plus. For more granular control (custom paths, intervals, status matching), use the VirtualServer CRD approach. For passive health checks (OSS), see Passive Health Checks in OSS Mappings.
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
spec:
  upstreams:
    - name: backend
      service: my-service
      port: 80
      healthCheck:  # health-checks
        enable: true
        fails: 3
        interval: 5s
        jitter: 2s
        mandatory: true  # health-checks-mandatory
        passes: 2
        path: /health
        persistent: true  # health-checks-mandatory-queue
        port: 8080
        statusMatch: "200-399"
      slowStart: 30s  # slow-start
Note: The VirtualServer CRD provides the most granular control over active health checks. Active health checks and slowStart require NGINX Plus. For passive health checks (OSS), see Passive Health Checks in OSS Mappings.

JWT Authentication

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
# No direct equivalent
# Requires external auth service
F5 NGINX Ingress Controller (Plus)
annotations:
  nginx.com/jwt-key: "my-jwk-secret"
  nginx.com/jwt-login-url: "https://login.example.com"
  nginx.com/jwt-realm: "API"
  nginx.com/jwt-token: "$http_authorization"
Note: The annotation approach requires a Kubernetes Secret containing the JWK. The Policy CRD approach is recommended for new deployments as it provides more granular control including JWKS URI support and key caching.
Kubernetes Ingress NGINX (Ingress-NGINX)
# No direct equivalent
# Requires external auth service
F5 NGINX Ingress Controller (Plus)
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: jwt-auth
spec:
  jwt:
    jwksURI: "https://idp.example.com/.well-known/jwks.json"  # jwt-key (enhanced)
    keyCache: 1h
    realm: "API"  # jwt-realm
    token: "$http_authorization"  # jwt-token
Note: The Policy CRD approach is recommended for new deployments. It supports JWKS URIs, key caching, and more granular configuration. The jwt-login-url annotation does not have a direct Policy CRD field — configure redirect logic separately via VirtualServer errorPages or server-snippets for 401 responses.

OIDC Authentication

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-always-set-cookie: "true"
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/verify"
F5 NGINX Ingress Controller
# Use snippets to propagate cookies from auth responses
annotations:
  nginx.org/location-snippets: |  # auth-always-set-cookie
    auth_request /auth;
    auth_request_set $auth_cookie $upstream_http_set_cookie;
    add_header Set-Cookie $auth_cookie;  # auth-always-set-cookie
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-always-set-cookie: "true"
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/verify"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # auth-always-set-cookie
        auth_request /auth;
        auth_request_set $auth_cookie $upstream_http_set_cookie;
        add_header Set-Cookie $auth_cookie;  # auth-always-set-cookie
      action:
        pass: backend
Note: The community auth-always-set-cookie ensures Set-Cookie headers from the auth service are forwarded to the client regardless of the response code. The F5 NGINX Ingress Controller's OIDC Policy handles cookies internally. For generic external auth, use nginx.org/location-snippets with auth_request_set to capture and forward cookies.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-cache-duration: "200 10m, 401 1m"
  nginx.ingress.kubernetes.io/auth-cache-key: "$remote_addr"
  nginx.ingress.kubernetes.io/auth-method: "GET"
  nginx.ingress.kubernetes.io/auth-proxy-set-headers: "default/auth-headers"
  nginx.ingress.kubernetes.io/auth-request-redirect: "https://app.example.com/callback"
  nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-User"
  nginx.ingress.kubernetes.io/auth-signin: "https://auth.example.com/oauth2/start"
  nginx.ingress.kubernetes.io/auth-signin-redirect-param: "rd"
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/oauth2/auth"
F5 NGINX Ingress Controller (Plus)
apiVersion: v1
kind: Secret
metadata:
  name: oidc-secret
type: nginx.org/oidc
data:
  client-secret: c2VjcmV0...
---
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: oidc-auth
spec:
  oidc:
    authEndpoint: "https://idp.example.com/authorize"  # auth-signin
    clientID: "my-client-id"
    clientSecret: oidc-secret
    jwksURI: "https://idp.example.com/.well-known/jwks.json"
    scope: "openid+profile+email"
    tokenEndpoint: "https://idp.example.com/token"  # auth-url
Note: Native OIDC support eliminates the need for oauth2-proxy sidecar. The community auth-url/auth-signin pattern uses the auth_request module (typically with oauth2-proxy) and supports any external auth service, not just OIDC. The community annotations auth-cache-duration, auth-cache-key, auth-method, auth-proxy-set-headers, auth-request-redirect, auth-response-headers, and auth-signin-redirect-param have no direct OIDC Policy equivalents — the Policy manages these concerns internally. If you need generic external auth (non-OIDC), use nginx.org/location-snippets with the auth_request directive.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-keepalive: "10"
  nginx.ingress.kubernetes.io/auth-keepalive-requests: "100"
  nginx.ingress.kubernetes.io/auth-keepalive-share-vars: "true"
  nginx.ingress.kubernetes.io/auth-keepalive-timeout: "60"
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/verify"
F5 NGINX Ingress Controller
# No direct auth-keepalive annotations; use snippets
# for auth_request subrequest customization.
annotations:
  nginx.org/location-snippets: |  # auth-keepalive
    auth_request /auth;
    auth_request_set $auth_user $upstream_http_x_auth_user;
    proxy_set_header X-Auth-User $auth_user;
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-keepalive: "10"
  nginx.ingress.kubernetes.io/auth-keepalive-requests: "100"
  nginx.ingress.kubernetes.io/auth-keepalive-share-vars: "true"
  nginx.ingress.kubernetes.io/auth-keepalive-timeout: "60"
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/verify"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # auth-keepalive
        auth_request /auth;
        auth_request_set $auth_user $upstream_http_x_auth_user;
        proxy_set_header X-Auth-User $auth_user;
      action:
        pass: backend
Note: The community controller's auth-keepalive, auth-keepalive-requests, auth-keepalive-share-vars, and auth-keepalive-timeout annotations configure keepalive connections to the external auth service. The F5 NGINX Ingress Controller doesn't have dedicated auth_request annotations. If using the F5 NGINX Ingress Controller OIDC Policy CRD, keepalive is managed internally. For generic external auth, use nginx.org/location-snippets with the auth_request directive.
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-snippet: |
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Forwarded-Method $request_method;
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/verify"
F5 NGINX Ingress Controller
annotations:
  nginx.org/location-snippets: |  # auth-snippet
    auth_request /auth;
    proxy_set_header X-Original-URI $request_uri;  # auth-snippet
    proxy_set_header X-Forwarded-Method $request_method;  # auth-snippet
Kubernetes Ingress NGINX (Ingress-NGINX)
annotations:
  nginx.ingress.kubernetes.io/auth-snippet: |
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Forwarded-Method $request_method;
  nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/verify"
F5 NGINX Ingress Controller
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: my-app
spec:
  host: app.example.com
  upstreams:
    - name: backend
      service: backend-svc
      port: 80
  routes:
    - path: /
      location-snippets: |  # auth-snippet
        auth_request /auth;
        proxy_set_header X-Original-URI $request_uri;  # auth-snippet
        proxy_set_header X-Forwarded-Method $request_method;  # auth-snippet
      action:
        pass: backend
Note: The community auth-snippet injects custom NGINX directives into the auth subrequest block. Since the F5 NGINX Ingress Controller uses the OIDC Policy CRD for authentication (or location-snippets for generic auth), any custom directives should be included directly in the nginx.org/location-snippets annotation alongside the auth_request directive.
Kubernetes Ingress NGINX (Ingress-NGINX)
# Opt out of global external auth for this Ingress
annotations:
  nginx.ingress.kubernetes.io/enable-global-auth: "false"
F5 NGINX Ingress Controller
# The F5 NGINX Ingress Controller does not have a global external
# auth feature. Authentication is configured per-resource
# via Policy CRDs or annotations.
# No migration action needed for this annotation.
Note: The community controller supports global external authentication via ConfigMap keys (global-auth-url, etc.). The enable-global-auth: "false" annotation opts an Ingress out of this global setting. The F5 NGINX Ingress Controller does not have global external auth — authentication is always configured per-resource (via OIDC/JWT Policy CRDs or location-snippets). This annotation can be safely removed during migration.

WAF (Web Application Firewall)

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
annotations:
  appprotect.f5.com/app-protect-enable: "True"
  appprotect.f5.com/app-protect-policy: "default/waf-policy"
  appprotect.f5.com/app-protect-security-log: "default/log-config"
  appprotect.f5.com/app-protect-security-log-destination: "syslog:server=syslog:514"
  appprotect.f5.com/app-protect-security-log-enable: "True"
Note: The appprotect.f5.com/ annotations enable F5 WAF for NGINX via Ingress annotations. The Policy CRD approach is recommended for new deployments as it provides more flexibility and reusability.
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
  name: waf-policy
spec:
  waf:
    apPolicy: "default/waf-policy"
    enable: true
    securityLogs:
      - enable: true
        apLogConf: "default/log-config"
        logDest: "syslog:server=syslog:514"
Note: F5 WAF for NGINX provides enterprise WAF capabilities beyond ModSecurity. The Policy CRD approach allows WAF policies to be shared across multiple VirtualServer routes. For community ModSecurity annotations, see the ModSecurity / WAF section in OSS Mappings.

ConfigMap Mappings

Both the community and F5 NGINX Ingress Controllers use a Kubernetes ConfigMap for global NGINX settings. Many keys share the same name, but some are renamed or have different semantics. The keys listed below are community ConfigMap keys that have an equivalent F5 NGINX Ingress Controller ConfigMap key.

Tip: A significant number of ConfigMap keys are identical between the two controllers — you can migrate those without any changes. The tables below highlight both the identical keys and the ones that need renaming or adjustment.
ConfigMap naming: The community controller typically uses a ConfigMap named ingress-nginx-controller. The F5 NGINX Ingress Controller uses nginx-config by default (configurable via --configmap flag). Remember to update the ConfigMap name in your deployment.

Identical Keys

These keys have the same name and semantics in both controllers. No changes are needed when migrating.

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  client-body-buffer-size: "16k"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  client-body-buffer-size: "16k"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  error-log-level: "warn"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  error-log-level: "warn"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  hsts: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  hsts: "true"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  hsts-include-subdomains: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  hsts-include-subdomains: "true"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  hsts-max-age: "31536000"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  hsts-max-age: "31536000"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  map-hash-bucket-size: "128"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  map-hash-bucket-size: "128"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  otel-service-name: "nginx-ingress"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  otel-service-name: "nginx-ingress"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-buffer-size: "8k"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-buffer-size: "8k"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-buffering: "on"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-buffering: "on"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-busy-buffers-size: "16k"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-busy-buffers-size: "16k"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-connect-timeout: "30"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-connect-timeout: "30"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-read-timeout: "120"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-read-timeout: "120"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-send-timeout: "60"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-send-timeout: "60"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  server-tokens: "false"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  server-tokens: "false"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  ssl-ciphers: "ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  ssl-ciphers: "ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  ssl-protocols: "TLSv1.2 TLSv1.3"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  ssl-protocols: "TLSv1.2 TLSv1.3"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  ssl-redirect: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  ssl-redirect: "true"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  variables-hash-bucket-size: "256"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  variables-hash-bucket-size: "256"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  variables-hash-max-size: "2048"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  variables-hash-max-size: "2048"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  worker-cpu-affinity: "auto"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  worker-cpu-affinity: "auto"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  worker-processes: "auto"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  worker-processes: "auto"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  worker-shutdown-timeout: "30s"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  worker-shutdown-timeout: "30s"

Proxy & Buffering

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-body-size: "8m"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  client-max-body-size: "8m"
Note: Both keys map to the NGINX client_max_body_size directive. The F5 NGINX Ingress Controller uses the NGINX-native naming convention.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-buffers-number: "4"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-buffers: "4 8k"
Note: The community key takes just a number (buffer count). The F5 NGINX Ingress Controller key takes the full NGINX proxy_buffers format: "number size" (e.g., "4 8k").

SSL/TLS

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  force-ssl-redirect: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  redirect-to-https: "true"
Note: The community controller uses an X-Forwarded-Proto header check to determine whether to redirect. The F5 NGINX Ingress Controller performs a direct HTTP-to-HTTPS redirect.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  hsts: "true"
  hsts-preload: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  hsts: "true"
Note: The F5 NGINX Ingress Controller's hsts: "true" includes the preload directive by default. There is no separate hsts-preload key — just enable hsts.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  ssl-dh-param: "default/dh-param"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  ssl-dhparam-file: "/etc/nginx/secrets/dhparam.pem"
Note: The community key references a Kubernetes secret name, while the F5 NGINX Ingress Controller key expects a file path to the DH parameters file mounted into the pod.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
# No equivalent ConfigMap key
# Redirect code is not globally configurable
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  redirect-to-https: "true"
  http-redirect-code: "308"
New in v5.4.0: The http-redirect-code ConfigMap key sets the global HTTP redirect status code used when redirecting to HTTPS (default: 301). Can also be set per-Ingress via the nginx.org/http-redirect-code annotation. Common values: 301 (permanent), 302 (temporary), 307 (temporary, preserves method), 308 (permanent, preserves method).

Logging

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  disable-access-log: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  access-log-off: "true"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  log-format-escape-json: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  log-format-escaping: "json"
Note: The community controller uses separate boolean keys (log-format-escape-json and log-format-escape-none). The F5 NGINX Ingress Controller uses a single key with a string value: "json", "default", or "none".
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  log-format-stream: '$remote_addr [$time_local]'
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  stream-log-format: '$remote_addr [$time_local]'
Note: The word order is swapped: community uses log-format-stream, while the F5 NGINX Ingress Controller uses stream-log-format.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  log-format-upstream: '$remote_addr - $request_id'
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  log-format: '$remote_addr - $request_id'

Network / Real IP

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  proxy-real-ip-cidr: "10.0.0.0/8"
  use-forwarded-headers: "true"
F5 NGINX Ingress Controller ConfigMap
data:
  set-real-ip-from: "10.0.0.0/8"
  real-ip-header: "X-Forwarded-For"
  real-ip-recursive: "true"
Note: The community controller uses proxy-real-ip-cidr and use-forwarded-headers. The F5 NGINX Ingress Controller uses the NGINX-native set-real-ip-from, real-ip-header, and real-ip-recursive ConfigMap keys.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  use-forwarded-headers: "true"
F5 NGINX Ingress Controller ConfigMap
data:
  real-ip-header: "X-Forwarded-For"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  use-proxy-protocol: "true"
F5 NGINX Ingress Controller ConfigMap
data:
  proxy-protocol: "true"
  set-real-ip-from: "0.0.0.0/0"
  real-ip-header: "proxy_protocol"
Note: When enabling PROXY protocol, also configure set-real-ip-from and real-ip-header to properly extract client IPs from the PROXY protocol header.

Worker & Performance

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  max-worker-connections: "16384"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  worker-connections: "16384"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  max-worker-open-files: "65536"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  worker-rlimit-nofile: "65536"

Upstream & Load Balancing

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  load-balance: "ewma"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  lb-method: "random two least_conn"
Note: The community controller defaults to round_robin and supports methods like ewma and least_conn. The F5 NGINX Ingress Controller defaults to random two least_conn and uses standard NGINX load balancing method names.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  upstream-keepalive-connections: "320"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  keepalive: "320"

Keepalive & Timeouts

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  keep-alive: "75"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  keepalive-timeout: "75s"
Note: Both map to the NGINX keepalive_timeout directive. The F5 NGINX Ingress Controller key uses the NGINX-native name and expects a time unit suffix (e.g., "75s").
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  keep-alive-requests: "1000"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  keepalive-requests: "1000"

Server & Hash Configuration

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  server-name-hash-bucket-size: "128"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  server-names-hash-bucket-size: "128"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  server-name-hash-max-size: "1024"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  server-names-hash-max-size: "1024"
Note: Subtle difference: the community uses server-name-hash-max-size and server-name-hash-bucket-size (singular "name"), while the F5 NGINX Ingress Controller uses server-names-hash-max-size and server-names-hash-bucket-size (plural "names") matching the NGINX directives.

Headers

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  hide-headers: "X-Powered-By,Server"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-hide-headers: "X-Powered-By,Server"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  proxy-real-ip-cidr: "10.0.0.0/8,172.16.0.0/12"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  set-real-ip-from: "10.0.0.0/8,172.16.0.0/12"
Note: Both map to the NGINX set_real_ip_from directive. The F5 NGINX Ingress Controller key uses the NGINX-native naming convention.

Protocol

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  use-http2: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  http2: "true"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  use-proxy-protocol: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  proxy-protocol: "true"

Snippets

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  main-snippet: |
    worker_rlimit_nofile 65535;
  http-snippet: |
    map $http_upgrade $connection_upgrade {
      default upgrade;
      '' close;
    }
  server-snippet: |
    add_header X-Custom "value";
  location-snippet: |
    proxy_cache_valid 200 10m;
  stream-snippet: |
    log_format stream '$remote_addr [$time_local]';
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  main-snippets: |
    worker_rlimit_nofile 65535;
  http-snippets: |
    map $http_upgrade $connection_upgrade {
      default upgrade;
      '' close;
    }
  server-snippets: |
    add_header X-Custom "value";
  location-snippets: |
    proxy_cache_valid 200 10m;
  stream-snippets: |
    log_format stream '$remote_addr [$time_local]';
Note: All snippet keys change from singular to plural: main-snippetmain-snippets, http-snippethttp-snippets, server-snippetserver-snippets, location-snippetlocation-snippets, stream-snippetstream-snippets.

OpenTelemetry

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  enable-opentelemetry: "true"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  otel-trace-in-http: "true"
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
data:
  otlp-collector-host: "otel-collector.observability"
  otlp-collector-port: "4317"
F5 NGINX Ingress Controller ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  otel-exporter-endpoint: "otel-collector.observability:4317"
Note: The community controller uses separate keys for host and port. The F5 NGINX Ingress Controller combines them into a single endpoint URL.

Snippet-Based Keys

These community ConfigMap keys have no direct equivalent in the F5 NGINX Ingress Controller. Use main-snippets, http-snippets, or server-snippets in the NIC ConfigMap to inject the equivalent NGINX directives.

Kubernetes Ingress NGINX (Ingress-NGINX)F5 NGINX Ingress Controller
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  access-log-path: "/var/log/nginx/access.log"
F5 NGINX Ingress Controller ConfigMap
data:
  http-snippets: |
    access_log /var/log/nginx/access.log;
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  custom-http-errors: "404,503"
F5 NGINX Ingress Controller ConfigMap
data:
  server-snippets: |
    error_page 404 503 @custom_errors;
Note: The community controller integrates with a default backend for custom error pages. The NIC requires manual error_page directives via snippets, typically combined with a custom error backend.
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  enable-brotli: "true"
  brotli-level: "6"
F5 NGINX Ingress Controller ConfigMap
# Brotli is not included in the default NGINX build.
# If using a custom build with the brotli module:
data:
  http-snippets: |
    brotli on;
    brotli_comp_level 6;
    brotli_types text/plain text/css application/json application/javascript;
Kubernetes Ingress NGINX (Ingress-NGINX) ConfigMap
data:
  error-log-path: "/var/log/nginx/error.log"
F5 NGINX Ingress Controller ConfigMap
data:
  main-snippets: |
    error_log /var/log/nginx/error.log warn;