In November 2025, Kubernetes SIG Network and the Security Response Committee announced that the community ingress-nginx controller would be retired, with best-effort maintenance until March 2026 and no releases or security fixes after that. Existing installations keep working, but running an internet-facing proxy without security updates is not a plan. The recommended direction is Gateway API, or another maintained Ingress controller if you need to stay on the Ingress API for now.

We run 140 Ingress objects across four clusters. This guide is the plan we followed. It is written to be reused: inventory, decide, convert, run in parallel, cut over, clean up.

Step 1: inventory what you actually use

The difficult part of leaving ingress-nginx is not the Ingress resource. It is the annotations, which encode behaviour that has no equivalent field in the Ingress API. List them first:

kubectl get ingress -A -o json \
  | jq -r '.items[] | .metadata.annotations // {} | keys[]' \
  | grep '^nginx.ingress.kubernetes.io/' | sort | uniq -c | sort -rn

Our top results:

 118 nginx.ingress.kubernetes.io/proxy-body-size
  97 nginx.ingress.kubernetes.io/force-ssl-redirect
  41 nginx.ingress.kubernetes.io/proxy-read-timeout
  23 nginx.ingress.kubernetes.io/rewrite-target
  12 nginx.ingress.kubernetes.io/auth-url
   9 nginx.ingress.kubernetes.io/configuration-snippet
   6 nginx.ingress.kubernetes.io/canary
   4 nginx.ingress.kubernetes.io/limit-rps

Also export the controller's ConfigMap: global settings like use-forwarded-headers, proxy-buffering, and custom log formats often matter more than per-Ingress annotations.

configuration-snippet and server-snippet deserve special attention. They inject raw nginx config, have been the source of serious security issues, and have no portable equivalent. Each one needs a human to read it and decide what it really does.

Step 2: choose an implementation

Gateway API is a specification; you still need a controller. Main criteria for us:

  • Conformance: the implementation passes the Gateway API conformance tests for the features we need (HTTPRoute, header modification, redirects, timeouts).
  • Policy support for what annotations used to do: auth, rate limits, body size, timeouts. Many of these are implementation-specific policy resources, so they still lock you in somewhat.
  • Operational fit: how it scales, how it reloads config, what metrics it exposes.
  • Long-term maintenance: a healthy maintainer base, which is exactly what ingress-nginx lacked.

Several mature implementations exist (Envoy Gateway, Istio, Cilium, NGINX Gateway Fabric, Traefik, Kong, and cloud provider gateways). We chose one based on a two-week trial with our ten most complex Ingresses.

Step 3: map concepts

ingress-nginx Gateway API
IngressClass + controller deployment GatewayClass + Gateway (owned by platform team)
Ingress rules.host + paths HTTPRoute hostnames + rules.matches
tls section Gateway listeners with certificateRefs
force-ssl-redirect HTTP listener + HTTPRoute with RequestRedirect filter
rewrite-target URLRewrite filter
canary annotations Weighted backendRefs
proxy-read-timeout HTTPRoute timeouts (where supported) or implementation policy
auth-url, limit-rps, proxy-body-size Implementation-specific policies

The ownership split is a real improvement: the platform team owns Gateways (listeners, certificates, addresses), application teams own HTTPRoutes and attach them to allowed Gateways.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop-api
  namespace: shop
spec:
  parentRefs:
    - name: public
      namespace: gateway-system
      sectionName: https
  hostnames: ["api.example.com"]
  rules:
    - matches:
        - path: {type: PathPrefix, value: /v2}
      filters:
        - type: URLRewrite
          urlRewrite:
            path: {type: ReplacePrefixMatch, replacePrefixMatch: /}
      backendRefs:
        - name: shop-api
          port: 8080

Step 4: convert, then review

ingress2gateway converts Ingress resources (including some ingress-nginx annotations) into Gateway API resources. We used it to generate a first draft per namespace and reviewed every diff by hand. Unsupported annotations are reported, which gave us a precise list of manual work.

ingress2gateway print --providers ingress-nginx --namespace shop > shop-gateway.yaml

Step 5: run both side by side

The new controller got its own load balancer address. For each host:

  1. Deploy the HTTPRoute to the new Gateway. The old Ingress keeps serving.
  2. Test with curl --resolve api.example.com:443:<new-ip> against real paths, including redirects, auth, uploads and websockets.
  3. Compare access logs and error rates using synthetic traffic.

Nothing changes for users until DNS moves.

Step 6: cut over host by host

Lower the DNS TTL to 60 seconds a day ahead. Switch one host's DNS record to the new address, watch error rates and latency for an hour, then continue. Start with internal and low-traffic hosts. Rollback is a DNS change back, which is why the old Ingress stays in place until the host has been stable for a week.

Watch for things that differ between proxies in subtle ways: default timeouts, maximum header sizes, how X-Forwarded-For is built, HTTP/2 to backends, and gzip. Most of our post-cutover issues were in this list.

Step 7: clean up

After all hosts moved: remove Ingress objects, uninstall ingress-nginx, delete its load balancer, and remove annotation-based tooling and dashboards. Update templates and docs so new services start with HTTPRoutes.

Common mistakes

Mistake Why it hurts Do this instead
Converting without an annotation inventory Behaviour silently lost Inventory annotations and controller ConfigMap first
Copying snippets into new raw config Same risks, new place Re-implement intent with supported features
Big-bang DNS switch Hard to isolate problems Host by host with low TTLs
Deleting old Ingresses on cutover day No fast rollback Keep them for a week after stability
Ignoring proxy default differences Timeouts and header limits change Compare defaults explicitly and test edge cases

Key takeaways

  • ingress-nginx stopped receiving releases and security fixes after March 2026; plan the move now.
  • Annotations and snippets are the real migration work; inventory them first.
  • Gateway API separates platform-owned Gateways from team-owned routes.
  • Convert with tooling, review by hand, run in parallel, cut over per host.
  • Keep a DNS-based rollback path until each host is proven.

References