Cloud & Delivery4 min read

Migrating From Ingress-NGINX After Its 2026 Retirement

A step-by-step Gateway API migration plan covering inventory, controller selection, annotations, traffic testing, WebSockets, DNS, and rollback.

JBy Jeffrey Klaassen van Oorschot

Ingress-NGINX was retired on March 24, 2026. Existing installations keep running, which is the uncomfortable part: nothing forces a migration until an unpatched vulnerability or incompatible platform change does. Kubernetes is explicit that there will be no further fixes or security releases. I would treat continued use as an owned risk with a short expiry, not as a stable default.

First prove whether you run it

Start with the controller, not Ingress objects. The Kubernetes steering committee suggests querying pods with the ingress-nginx application label. I also search Helm releases, GitOps repositories, cluster add-ons, admission policies, DNS records, and cloud load balancers. Old clusters and preview environments are easy to miss.

Create an inventory per cluster: controller image and chart, public IPs, namespaces, ingress classes, certificates, DNS names, and owning teams. Then export every Ingress and collect annotations. The annotation list is the real migration backlog.

Discovery commands to start the inventory
kubectl get pods --all-namespaces   --selector app.kubernetes.io/name=ingress-nginx

kubectl get ingress --all-namespaces   -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,CLASS:.spec.ingressClassName,HOSTS:.spec.rules[*].host'

kubectl get ingress --all-namespaces -o yaml > ingress-inventory.yaml

Translate behaviour, not YAML

I classify annotations into routing, security, transport, capacity, observability, and controller-specific extensions. Rewrites, regex paths, authentication subrequests, snippets, body limits, timeouts, forwarded headers, CORS, canaries, and source-IP handling all need an explicit destination or an explicit decision to remove them.

Some behaviour belongs in HTTPRoute. Some belongs in the Gateway or controller policy. Some should move into the application or disappear because it was an unsafe workaround. A mechanical conversion tool is useful for a first draft, but it cannot know the product reason behind an annotation.

  • Uploads: maximum body size and request timeout
  • WebSockets: upgrade support, idle timeout, and draining
  • Authentication: identity headers and failure redirects
  • Client IP: trusted hops and forwarded-header ownership
  • Rewrites: exact path and query-string semantics

Choose an implementation, not only Gateway API

Gateway API defines resources; a controller implements them. I compare conformance for the required Gateway API version, supported features, cloud integration, operational maturity, security process, upgrade policy, metrics, status conditions, and team familiarity. Gateway API 1.5 listed seven fully conformant implementations at release, but conformance does not mean identical extensions or operations.

I install the candidate in a non-production cluster and migrate one representative route: TLS, redirects, a normal API, a large upload, a WebSocket, and an error path. That route becomes the compatibility test for controller upgrades too.

Build a parallel path

Run the new controller beside Ingress-NGINX with a separate load balancer and test hostname. Generate Gateway and HTTPRoute resources from reviewed configuration. Validate Accepted, Programmed, and backend status conditions; a resource being created does not prove traffic is ready.

A deliberately small HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: portfolio
spec:
  parentRefs:
    - name: public-web
  hostnames:
    - jeffsmind.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: portfolio
          port: 80

Compare traffic before switching DNS

Replay sanitized production requests or mirror safe traffic and compare status, headers, redirects, body hashes where stable, upstream selection, latency, and error rate. Test malformed requests and dependency failure. For WebSockets, observe connection duration and reconnect behaviour through a rolling controller deployment.

Lower DNS TTL before the move, but remember existing connections and resolver caches outlive the ideal TTL. Move a small set of hosts first. Keep Ingress-NGINX and its configuration deployable until the observation window closes. Define rollback thresholds before cutover, then remove the old controller, load balancer, RBAC, webhook, and charts when the migration is complete.

Use this in practice

  • Inventory controllers, Ingresses, annotations, DNS, and owners
  • Select a controller by conformance and operations
  • Test uploads, WebSockets, auth, rewrites, and client IPs
  • Run both paths and compare responses
  • Cut over hosts gradually with a practiced rollback
  • Remove old controller privileges and infrastructure

Keep reading