NGINX Ingress Controller Deprecation: Complete Migration Guide to Gateway API

The Cloud Native Computing Foundation (CNCF) has announced the deprecation of the NGINX Ingress Controller project, with official support ending in March 2026. This significant announcement marks a turning point in Kubernetes networking, as the community transitions from the traditional Ingress API to the more modern and powerful Gateway API. Organizations using NGINX Ingress Controller need to understand the implications and plan their migration to Gateway API implementations.

Understanding the Deprecation

Why the Deprecation?

The NGINX Ingress Controller deprecation stems from several factors:

  • Maintenance Burden: Keeping up with Kubernetes changes and security patches
  • Limited Capabilities: The Ingress API’s limitations restrict advanced networking features
  • Security Concerns: Ongoing security maintenance challenges
  • Ecosystem Evolution: The industry’s shift toward Gateway API standards
  • Resource Allocation: Community resources better focused on Gateway API implementations

Timeline and Support

  • Deprecation Announced: September 2025
  • Final Release: December 2025
  • End of Life: March 2026
  • Security Updates: Critical security patches through March 2026
  • No New Features: No new feature development after deprecation announcement

Gateway API: The Path Forward

The Gateway API represents the evolution of Kubernetes ingress, designed to address Ingress API limitations:

Key Advantages

  • Role-Oriented Design: Better separation of concerns across infrastructure, operators, and developers
  • Advanced Routing: Header-based, query parameter, and method-based routing
  • Cross-Namespace Support: Native support for routing across namespaces
  • Type Safety: Better validation and error handling
  • Extensibility: Standard extension points for vendor-specific features
  • Portability: Works across different implementations and cloud providers

NGINX Gateway Fabric

NGINX’s official Gateway API implementation, NGINX Gateway Fabric, provides a seamless path for NGINX Ingress users:

  • NGINX Data Plane: Leverages proven NGINX technology
  • Gateway API Compliant: Full implementation of Gateway API specifications
  • Production Ready: Battle-tested in production environments
  • Feature Parity: Many features from NGINX Ingress plus Gateway API enhancements

Migration Strategy

Phase 1: Assessment and Planning

1. Inventory Current Ingress Resources

Document all current Ingress resources:

# List all Ingress resources across all namespaces
kubectl get ingress --all-namespaces -o wide

# Export configurations
kubectl get ingress --all-namespaces -o yaml > ingress-backup.yaml

# Identify annotations and custom configurations
kubectl get ingress --all-namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.namespace}{"\t"}{.metadata.annotations}{"\n"}{end}'

2. Analyze Dependencies

Identify dependencies and integrations:

  • Monitoring: Prometheus, Grafana integrations
  • Certificate Management: cert-manager, Let’s Encrypt
  • Service Mesh: Istio, Linkerd integrations
  • Custom Configurations: NGINX-specific annotations
  • Load Balancing: Session affinity, health checks

3. Choose Gateway API Implementation

Select a Gateway API implementation:

NGINX Gateway Fabric (Recommended for NGINX users):

  • Direct migration path from NGINX Ingress
  • Familiar NGINX features and behaviors
  • Proven NGINX data plane

Istio Gateway:

  • Full service mesh integration
  • Advanced traffic management
  • Multi-cluster support

Kong Gateway:

  • Rich plugin ecosystem
  • Advanced API management features
  • Enterprise features

Envoy Gateway:

  • Vendor-neutral implementation
  • High performance
  • CNCF project

Phase 2: Gateway API Setup

Install NGINX Gateway Fabric

# Add NGINX Gateway Fabric Helm repository
helm repo add nginx-gateway-fabric https://nginxinc.github.io/nginx-gateway-fabric-helm-charts
helm repo update

# Install NGINX Gateway Fabric
helm install nginx-gateway-fabric nginx-gateway-fabric/nginx-gateway-fabric \
  --namespace nginx-gateway \
  --create-namespace \
  --set deployment.image.repository=nginx/nginx-gateway-fabric \
  --set deployment.image.tag=latest

# Verify installation
kubectl get pods -n nginx-gateway
kubectl get gatewayclass

Create GatewayClass

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx-gateway
spec:
  controllerName: gateway.nginx.org/gateway-controller
  description: NGINX Gateway Fabric for production use

Create Gateway Instance

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
  namespace: nginx-gateway
spec:
  gatewayClassName: nginx-gateway
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - name: production-tls-cert
        namespace: cert-manager

Phase 3: Migration Execution

Convert Simple Ingress to HTTPRoute

Original Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: production
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - example.com
    - www.example.com
    secretName: example-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Converted HTTPRoute:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web-route
  namespace: production
spec:
  parentRefs:
  - name: production-gateway
    namespace: nginx-gateway
  hostnames:
  - example.com
  - www.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: web-service
      port: 80

Handle NGINX-Specific Annotations

Many NGINX Ingress annotations have Gateway API equivalents:

Rate Limiting:

# NGINX Ingress Annotation
annotations:
  nginx.ingress.kubernetes.io/limit-rps: "100"

# Gateway API Equivalent (using NGINX Gateway Fabric extension)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: rate-limited-route
spec:
  parentRefs:
  - name: production-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    filters:
    - type: ExtensionRef
      extensionRef:
        group: gateway.nginx.org
        kind: RateLimitPolicy
        name: rate-limit-policy
---
apiVersion: gateway.nginx.org/v1alpha1
kind: RateLimitPolicy
metadata:
  name: rate-limit-policy
spec:
  rate: 100
  period: 1s

SSL Redirect:

# NGINX Ingress Annotation
annotations:
  nginx.ingress.kubernetes.io/ssl-redirect: "true"

# Gateway API - Use HTTPS listener with redirect filter
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-route
spec:
  parentRefs:
  - name: production-gateway
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301

Path Rewriting:

# NGINX Ingress Annotation
annotations:
  nginx.ingress.kubernetes.io/rewrite-target: /$1

# Gateway API Equivalent
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: rewrite-route
spec:
  parentRefs:
  - name: production-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1
    filters:
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplacePrefixMatch
          replacePrefixMatch: /v1
    backendRefs:
    - name: api-service
      port: 8080

CORS Configuration:

# NGINX Ingress Annotations
annotations:
  nginx.ingress.kubernetes.io/enable-cors: "true"
  nginx.ingress.kubernetes.io/cors-allow-origin: "*"

# Gateway API Extension (NGINX Gateway Fabric)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cors-route
spec:
  parentRefs:
  - name: production-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    filters:
    - type: ExtensionRef
      extensionRef:
        group: gateway.nginx.org
        kind: CORSPolicy
        name: cors-policy
---
apiVersion: gateway.nginx.org/v1alpha1
kind: CORSPolicy
metadata:
  name: cors-policy
spec:
  allowOrigins:
  - "*"
  allowMethods:
  - GET
  - POST
  - PUT
  - DELETE
  allowHeaders:
  - "*"

Phase 4: Advanced Migrations

Session Affinity

# NGINX Ingress Annotation
annotations:
  nginx.ingress.kubernetes.io/affinity: "cookie"
  nginx.ingress.kubernetes.io/session-cookie-name: "route"
  nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
  nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"

# Gateway API - Use Service with sessionAffinity
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  ports:
  - port: 80
    targetPort: 8080

Canary Deployments

# NGINX Ingress Canary Annotations
annotations:
  nginx.ingress.kubernetes.io/canary: "true"
  nginx.ingress.kubernetes.io/canary-weight: "10"

# Gateway API - Native Traffic Splitting
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: canary-route
spec:
  parentRefs:
  - name: production-gateway
  hostnames:
  - example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: stable-service
      port: 80
      weight: 90
    - name: canary-service
      port: 80
      weight: 10

Header-Based Routing

# Gateway API provides native header matching
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-routing
spec:
  parentRefs:
  - name: production-gateway
  rules:
  - matches:
    - headers:
      - name: x-api-version
        value: v2
    backendRefs:
    - name: api-v2-service
      port: 8080
  - matches:
    - headers:
      - name: x-api-version
        value: v1
    backendRefs:
    - name: api-v1-service
      port: 8080

Phase 5: Testing and Validation

Testing Strategy

  1. Parallel Deployment: Run both Ingress and Gateway API in parallel
  2. Traffic Splitting: Gradually shift traffic to Gateway API
  3. Monitoring: Compare metrics and performance
  4. Validation: Verify all functionality works correctly
# Gradual traffic migration
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: migration-route
spec:
  parentRefs:
  - name: production-gateway
  rules:
  - backendRefs:
    # Keep old Ingress service initially
    - name: ingress-service
      port: 80
      weight: 50
    # Route to new Gateway API
    - name: gateway-service
      port: 80
      weight: 50

Validation Checklist

  • All routes working correctly
  • TLS/SSL certificates functioning
  • Load balancing working as expected
  • Session affinity maintained (if used)
  • Rate limiting applied correctly
  • Monitoring and metrics collected
  • Performance meets or exceeds previous setup
  • Security policies enforced

Certificate Management Migration

cert-manager Integration

cert-manager works seamlessly with Gateway API:

# Certificate resource (same as before)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-tls
  namespace: cert-manager
spec:
  secretName: example-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - example.com
  - www.example.com

# Reference in Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
spec:
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: example-tls
        namespace: cert-manager

Monitoring and Observability

Metrics Collection

NGINX Gateway Fabric exposes Prometheus metrics:

apiVersion: v1
kind: Service
metadata:
  name: nginx-gateway-metrics
  namespace: nginx-gateway
  labels:
    app: nginx-gateway-fabric
spec:
  ports:
  - name: metrics
    port: 9113
    targetPort: 9113
  selector:
    app: nginx-gateway-fabric

Prometheus scraping configuration:

apiVersion: v1
kind: ServiceMonitor
metadata:
  name: nginx-gateway-metrics
spec:
  selector:
    matchLabels:
      app: nginx-gateway-fabric
  endpoints:
  - port: metrics
    interval: 30s

Logging

Gateway API implementations provide structured logging compatible with existing log aggregation systems.

Rollback Plan

If Issues Arise

  1. Keep Ingress Resources: Don’t delete old Ingress resources immediately
  2. Traffic Redirection: Switch traffic back to Ingress controller
  3. Investigate Issues: Debug Gateway API configuration
  4. Fix and Retry: Correct issues and migrate again
# Switch traffic back to Ingress
kubectl scale deployment nginx-gateway-fabric --replicas=0 -n nginx-gateway
kubectl scale deployment ingress-nginx-controller --replicas=3 -n ingress-nginx

Best Practices

1. Namespace Organization

Organize Gateway resources logically:

# Infrastructure namespace for Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
  namespace: infrastructure

# Application namespace for HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-route
  namespace: applications
spec:
  parentRefs:
  - name: shared-gateway
    namespace: infrastructure

2. Reference Grants for Cross-Namespace

Enable secure cross-namespace references:

apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
  name: allow-apps-to-infra
  namespace: infrastructure
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: applications
  to:
  - group: gateway.networking.k8s.io
    kind: Gateway

3. Gradual Migration

Migrate namespace by namespace:

  1. Start with non-critical applications
  2. Validate thoroughly
  3. Gradually migrate production workloads
  4. Monitor performance and stability

Common Challenges and Solutions

Challenge 1: Complex Annotations

Problem: Extensive use of NGINX-specific annotations

Solution: Map annotations to Gateway API features or use implementation-specific extensions

Challenge 2: Custom Configurations

Problem: Custom NGINX configurations not directly supported

Solution: Use Gateway API extension mechanisms or implementation-specific features

Challenge 3: Third-Party Integrations

Problem: Tools expecting NGINX Ingress format

Solution: Update tools to support Gateway API or use translation layers

Resources and Support

Documentation

Community Support

Conclusion

The deprecation of NGINX Ingress Controller marks an important transition in Kubernetes networking. While this change requires migration effort, it presents an opportunity to adopt more powerful, standardized, and future-proof networking solutions.

Key takeaways:

  • Plan Early: Start migration planning well before March 2026
  • Choose Implementation: Select a Gateway API implementation that fits your needs
  • Gradual Migration: Migrate gradually with proper testing
  • Leverage Advantages: Take advantage of Gateway API’s enhanced capabilities
  • Stay Informed: Follow Gateway API development and best practices

The Gateway API ecosystem is mature, well-supported, and ready for production use. Organizations that migrate successfully will benefit from better security, more advanced features, and a more maintainable networking infrastructure.

The transition from NGINX Ingress Controller to Gateway API represents progress in Kubernetes networking, and with proper planning and execution, organizations can make this transition smoothly while gaining significant advantages in the process.


For more information about Gateway API migration, visit the official Gateway API documentation and NGINX Gateway Fabric repository.