Kubernetes KubernetesIngress

NGINX Ingress Controller Retirement: Your Complete Migration Guide for March 2026

Kubernetes is retiring ingress-nginx by March 2026. Learn why this affects 40-62% of clusters and get step-by-step migration instructions.

K

DevOps & Kubernetes Consultants

15 min read

Breaking: NGINX Ingress Controller Reaches End of Life

The Kubernetes Security Response Committee and SIG Network have announced that Ingress NGINX will be fully retired in March 2026, with no further releases, bugfixes, or security vulnerability updates afterward. This decision impacts an estimated 40-62% of all Kubernetes clusters worldwide, making it one of the most significant infrastructure changes in Kubernetes history.

If you’re running Kubernetes in production, this announcement demands immediate attention. Your ingress controller powers every external request to your applications, and running unmaintained infrastructure with known security vulnerabilities is not an option.

Why Is NGINX Ingress Being Retired?

The breadth and flexibility of Ingress NGINX has caused maintenance challenges, and what were once considered helpful options have sometimes come to be considered serious security flaws, such as the ability to add arbitrary NGINX configuration directives via the “snippets” annotations.

The reality is stark: Ingress NGINX has always struggled with insufficient or barely-sufficient maintainership, with only one or two people doing development work on their own time, after work hours and on weekends. The technical debt has become insurmountable, and the Kubernetes community has exhausted efforts to find sustainable support.

Key factors behind the retirement:

  • Insufficient maintainership: Years of running on volunteer weekend work
  • Security concerns: Features like configuration snippets have become attack vectors
  • Technical debt: Flexibility turned into unmanageable complexity
  • Sustainability: The maintenance burden permanently exceeds contribution rates

Immediate Impact and Timeline

Here’s what you need to know right now:

Current Status (November 2025)

  • Best-effort maintenance continues
  • No new features being added
  • Critical security patches only

March 2026 - Full Retirement

  • No more releases or updates
  • No security patches for new vulnerabilities
  • GitHub repositories become read-only
  • Existing installations continue working (but unpatched)

Your Action Timeline

  • NOW - December 2025: Complete assessment and planning
  • January 2026: Test migrations in staging environments
  • February 2026: Execute production migrations
  • March 2026: Finalize all migrations before retirement

Step 1: Verify If You’re Using Ingress NGINX

Before panicking, confirm whether you’re actually using ingress-nginx. Run this command with cluster admin permissions:

kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx

If you see pods returned, you’re using ingress-nginx and need to migrate.

Additional verification commands:

# Check ingress class
kubectl get ingressclass

# List all ingress resources
kubectl get ingress --all-namespaces

# Check Helm releases
helm list --all-namespaces | grep ingress-nginx

Step 2: Assess Your Current Configuration

Document your existing setup before making any changes:

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

# Export ingress-nginx configuration
kubectl get configmap -n ingress-nginx ingress-nginx-controller -o yaml > nginx-config-backup.yaml

# Document custom annotations used
kubectl get ingress --all-namespaces -o json | jq '.items[].metadata.annotations'

# Check for custom snippets (security risk)
kubectl get ingress --all-namespaces -o json | jq '.items[] | select(.metadata.annotations | to_entries[] | select(.key | contains("snippet")))'

Create an inventory spreadsheet with:

  • All ingress resources and their namespaces
  • Custom annotations being used
  • TLS/SSL certificate configurations
  • Rate limiting and authentication rules
  • Custom NGINX configuration snippets
  • External dependencies (cert-manager, external-dns, etc.)

Step 3: Choose Your Migration Path

The Kubernetes community recommends several alternatives. Here’s how to choose:

Best for: Future-proof infrastructure, CNCF-backed projects, teams wanting modern standards

Gateway API is the official successor to Ingress, offering better functionality and CNCF backing.

Advantages:

  • Official Kubernetes networking API
  • Role-oriented design (Infrastructure vs. Application teams)
  • More expressive than Ingress
  • Growing ecosystem support
  • CNCF project with strong backing

Migration Complexity: Medium to High (API paradigm shift)

Option 2: Cloud-Native Solutions

Best for: Cloud-hosted clusters, teams preferring managed services

  • AWS: AWS Load Balancer Controller
  • Azure: Azure Application Gateway Ingress Controller
  • GCP: GKE Ingress
  • DigitalOcean: DigitalOcean Load Balancer

Advantages:

  • Tight cloud integration
  • Managed and maintained by cloud providers
  • Native features (WAF, DDoS protection)
  • Zero maintenance overhead

Migration Complexity: Low to Medium

Option 3: Alternative Ingress Controllers

Best for: Teams wanting minimal changes, specific feature requirements

Popular alternatives include:

  • Traefik: Modern, feature-rich, excellent for microservices
  • HAProxy Ingress: Best performance, proven reliability
  • Kong Ingress: API gateway features, enterprise support
  • Contour: Envoy-based, VMware-backed
  • F5 NGINX Ingress Controller: Commercial support, NGINX Plus features

Migration Complexity: Low (similar concepts to ingress-nginx)

Step 4: Migration to Gateway API (Detailed Steps)

Here’s a complete migration guide for moving to Gateway API with Envoy Gateway:

Install Envoy Gateway

# Install Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

# Install Envoy Gateway
helm repo add envoy-gateway https://gateway.envoyproxy.io
helm repo update
helm install eg envoy-gateway/gateway-helm --namespace envoy-gateway-system --create-namespace

Create Gateway Resource

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg-gateway
  namespace: default
spec:
  gatewayClassName: eg
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: tls-secret
      allowedRoutes:
        namespaces:
          from: All

Convert Ingress to HTTPRoute

Before (Ingress):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kubeace-app
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: app.kubeace.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080
  tls:
    - hosts:
        - app.kubeace.com
      secretName: tls-secret

After (HTTPRoute):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: kubeace-app
spec:
  parentRefs:
    - name: eg-gateway
      namespace: default
  hostnames:
    - "app.kubeace.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: api-service
          port: 8080

Handle Common Annotations

URL Rewriting:

# Ingress annotation: nginx.ingress.kubernetes.io/rewrite-target: /$2
# Gateway API equivalent:
rules:
  - matches:
      - path:
          type: RegularExpression
          value: /old(/.*)?
    filters:
      - type: URLRewrite
        urlRewrite:
          path:
            type: ReplacePrefixMatch
            replacePrefixMatch: /new

Rate Limiting:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: rate-limit-policy
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: kubeace-app
  rateLimit:
    type: Local
    local:
      rules:
        - limit:
            requests: 100
            unit: Minute

CORS Configuration:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: cors-policy
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: kubeace-app
  cors:
    allowOrigins:
      - "https://kubeace.com"
    allowMethods:
      - GET
      - POST
    allowHeaders:
      - "*"

Step 5: Migration to Traefik (Alternative Path)

For teams preferring an Ingress-compatible controller:

Install Traefik

# Add Traefik Helm repository
helm repo add traefik https://traefik.github.io/charts
helm repo update

# Install Traefik
helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace \
  --set ports.web.redirectTo.port=websecure

Update Ingress Resources

The good news: Most Ingress resources work with minimal changes.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kubeace-app
  annotations:
    # Change ingress class
    kubernetes.io/ingress.class: traefik
    # Traefik-specific annotations (optional)
    traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
spec:
  # Or use ingressClassName field
  ingressClassName: traefik
  rules:
    - host: app.kubeace.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080

Create Middleware for Advanced Features

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rate-limit
spec:
  rateLimit:
    average: 100
    burst: 50
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
spec:
  redirectScheme:
    scheme: https
    permanent: true

Common Migration Challenges and Solutions

Challenge 1: Custom NGINX Configuration Snippets

Problem: Snippets won’t work in Gateway API or other controllers.

Solution:

  • Identify all ingresses using snippets: kubectl get ingress -A -o json | jq '.items[] | select(.metadata.annotations | to_entries[] | select(.key | contains("snippet")))'
  • Reimplement using native features of new controller
  • For Gateway API, use Envoy filters or Extension APIs
  • For Traefik, use Middleware resources
  • Document and test each custom configuration

Challenge 2: Rate Limiting Migration

Problem: NGINX rate limiting annotations need conversion.

Solution:

# Gateway API - BackendTrafficPolicy
# Traefik - Middleware with rateLimit
# Ensure per-client vs global rate limiting matches requirements

Challenge 3: Authentication/Authorization

Problem: NGINX auth annotations (basic auth, OAuth2) need replacement.

Solution:

  • Gateway API: Use SecurityPolicy resources
  • Traefik: Use BasicAuth or ForwardAuth middleware
  • Consider external auth services (OAuth2 Proxy, Keycloak)

Challenge 4: WebSocket Support

Problem: Ensuring WebSocket connections work with new controller.

Solution:

  • Test WebSocket-specific paths
  • Verify timeout configurations
  • Check upgrade header handling
# Gateway API supports WebSockets by default
# Traefik: usually works without changes

Monitoring Your New Controller

Set up comprehensive monitoring immediately:

# Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: gateway-controller
spec:
  selector:
    matchLabels:
      app: envoy-gateway
  endpoints:
    - port: metrics
      interval: 30s

Key metrics to track:

  • Request rate and latency (p50, p95, p99)
  • Error rates (4xx, 5xx)
  • TLS handshake failures
  • Backend connection pool usage
  • CPU and memory utilization
  • Configuration reload times

Security Considerations Post-Migration

The retirement is partly due to security concerns. Ensure your new setup is secure:

  1. Eliminate configuration snippets: Never allow arbitrary configuration injection
  2. Enable mTLS: Use service mesh or controller features for mutual TLS
  3. Implement WAF: Consider ModSecurity or cloud WAF solutions
  4. Regular updates: Ensure your new controller has active maintenance
  5. RBAC controls: Restrict who can create/modify ingress resources
  6. Network policies: Implement pod-to-pod network restrictions
  7. Secret management: Use external secret managers (Vault, Azure Key Vault, AWS Secrets Manager)

Resources and Support

Conclusion: Don’t Wait Until March

The Kubernetes community recommends that all Ingress NGINX users begin migration to Gateway API or another Ingress controller immediately. With only four months until the March 2026 deadline, delaying this migration puts your infrastructure at risk.

The retirement of ingress-nginx marks a significant shift toward more sustainable, secure, and modern networking solutions in Kubernetes. While migration requires effort, it’s an opportunity to adopt better architectures and eliminate technical debt.

The maintainers of ingress-nginx deserve immense gratitude for years of volunteer work powering billions of requests worldwide. Now it’s our responsibility to migrate gracefully and support the next generation of Kubernetes networking.

Need help with your migration? At KubeAce, we specialize in zero-downtime Kubernetes migrations and infrastructure modernization. Contact us for a migration assessment and implementation support.