DEV Community

Cover image for Kubernetes Ingress-NGINX Is Retiring in March 2026
Tahmid Bin Taslim Rafi
Tahmid Bin Taslim Rafi

Posted on

Kubernetes Ingress-NGINX Is Retiring in March 2026

TL;DR: If you run ingress-nginx in production, treat March 2026 as a hard deadline. After retirement, you should not expect new releases or security fixes. Start migrating to Kubernetes Gateway API (or another supported ingress/gateway implementation) now.


Quick checklist

  • List every Ingress + annotations
  • Identify snippet usage
  • Install Gateway API CRDs
  • Choose a Gateway API implementation
  • Convert 1 low-risk service first
  • Run parallel + test
  • Cut over with rollback ready
  • Repeat service-by-service

Why you should care?

If your cluster’s north–south traffic depends on Ingress-NGINX, you’re likely relying on:

  • TLS termination
  • path/host routing
  • HTTP header rewrites
  • rate limits / auth integrations
  • “magic” annotation behaviors

Retirement means: your current setup may keep running… until a CVE, a Kubernetes upgrade, or a cloud load balancer change turns it into a pager storm.


Ingress vs Gateway API

Ingress was a simple contract:

  • one resource (Ingress)
  • annotations for “advanced” behaviors
  • controller-specific knobs

Gateway API splits responsibilities and makes traffic management portable across implementations:

  • GatewayClasswhich controller provides gateway capability
  • Gatewaythe actual data-plane entry point (listeners, TLS, addresses)
  • HTTPRoute / TCPRoute / GRPCRouterouting rules
  • policies (e.g., TLS policies) — portable behaviors that don’t require annotations

How Resources are connected?

Kubernetes Ingress-NGINX


Migration plan

Step 0 — Inventory what you’re actually using

Most Ingress-NGINX clusters are annotation-heavy.

Run these to find your “hidden complexity”:

# List all ingresses and controllers
kubectl get ingress -A

# Show every annotation in ingresses (quick scan)
kubectl get ingress -A -o json | jq -r '
  .items[] |
  "\(.metadata.namespace)/\(.metadata.name)\t" +
  ((.metadata.annotations // {}) | to_entries | map("\(.key)=\(.value)") | join("; "))
'

# Find the scary ones (snippets, custom templates)
kubectl get ingress -A -o json | jq -r '
  .items[] |
  select((.metadata.annotations // {}) | has("nginx.ingress.kubernetes.io/server-snippet")
  or has("nginx.ingress.kubernetes.io/configuration-snippet")) |
  "\(.metadata.namespace)/\(.metadata.name)"
'
Enter fullscreen mode Exit fullscreen mode

Make a list of:

  • TLS behavior (single cert? wildcard? per-host?)
  • rewrites and redirects
  • auth (OIDC, basic auth, external auth)
  • rate-limits
  • custom NGINX snippets

Rule: the more snippets you have, the more you must treat this as an application migration—not just YAML changes.


Step 1 — Install Gateway API CRDs

You can install the Gateway API CRDs via your preferred method (Helm / kustomize / manifests), but don’t attach production traffic yet.

Verify CRDs exist:

kubectl get crd | grep gateway
kubectl api-resources | grep -E 'gateway|httproute|tcproute|grpcroute'
Enter fullscreen mode Exit fullscreen mode

Step 2 — Pick an implementation

Gateway API is a spec. You still need an implementation.

Common choices:

  • Managed gateways (cloud-provider)
  • Service mesh gateways
  • Dedicated gateway controllers

Pick based on:

  • features you need (TCP/UDP? WAF? mTLS?)
  • operational complexity
  • observability and rate-limiting
  • support and upgrade story

Step 3 — Convert one Ingress

Let’s migrate a typical Ingress:

Before: Ingress-NGINX

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app
  namespace: prod
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /?(.*)
        pathType: Prefix
        backend:
          service:
            name: app-svc
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode

After: Gateway + HTTPRoute

Note: the exact fields can vary slightly by implementation.

Gateway

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
  namespace: prod
spec:
  gatewayClassName: example-gatewayclass
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: app.example.com
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: app-tls
Enter fullscreen mode Exit fullscreen mode

HTTPRoute

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-route
  namespace: prod
spec:
  parentRefs:
  - name: prod-gateway
  hostnames:
  - app.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: app-svc
      port: 80
Enter fullscreen mode Exit fullscreen mode

Rewrite behavior: what to do instead of rewrite-target

Ingress-NGINX had lots of rewrite tricks.

In Gateway API, you’ll typically use filters (implementation support varies):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-route
  namespace: prod
spec:
  parentRefs:
  - name: prod-gateway
  hostnames:
  - app.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    filters:
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplacePrefixMatch
          replacePrefixMatch: /
    backendRefs:
    - name: app-svc
      port: 80
Enter fullscreen mode Exit fullscreen mode

If your rewrite logic depends on regex capture groups (/$1), you may need to:

  • refactor routes
  • move logic into the app
  • or pick an implementation that supports your needs

Step 4 — Run both in parallel

Option A: Separate DNS names (cleanest)

  • Keep app.example.com on Ingress-NGINX
  • Create app-gw.example.com on Gateway
  • Test, load-test, verify metrics
  • Switch DNS once stable

Option B: Weighted traffic (advanced)

Some gateways support traffic splitting between backends or routes.

If supported, roll out progressively:

  • 1% → 10% → 50% → 100%

Step 5 — Validate

Functional checks

# TLS and SNI
curl -vk https://app.example.com/

# Host routing
curl -H 'Host: app.example.com' https://<gateway-lb-ip>/

# Path behavior
curl -I https://app.example.com/api/health
Enter fullscreen mode Exit fullscreen mode

Load and latency checks

  • p95/p99 latency
  • error rate (4xx/5xx)
  • upstream timeouts
  • connection reuse

Common pitfalls

  1. Annotation-only features: Snippets and custom NGINX directives rarely translate 1:1.
  2. Auth flows: External auth in NGINX may need a dedicated auth service or gateway plugin.
  3. TLS edge cases: Wildcard certs + SNI + multiple hosts = test carefully.
  4. Path matching differences: Prefix vs regex behaviors differ.
  5. Observability: Make sure you have equivalent access logs, metrics, tracing.

Rollback plan

  • Keep Ingress-NGINX resources intact during migration.
  • Make DNS changes reversible.
  • Use low TTLs during cutover.
  • Maintain a “back to old gateway” runbook.

Rollback should be one command or one DNS change, not a 2-hour YAML surgery.


Top comments (0)