Skip to main content
Logo
Overview

Ingress-NGINX Is Dead: What to Migrate To in 2026

May 28, 2026
10 min read

The Kubernetes ingress-nginx project officially retired in March 2026. No more releases, no more bugfixes, no more CVE patches. If you’re still running it — and most clusters in the wild are — you’re now on borrowed time. The first post-EOL CVE is going to hurt, and “we’ll migrate next quarter” stops being a defensible answer the moment Trivy starts screaming at your platform team.

I’ve spent the last few weeks helping two teams pick replacements and shadow-deploy them. One was an EKS shop with about 80 services behind ingress-nginx; the other was a bare-metal cluster running MetalLB. Different shapes, same problem. What follows is the comparison I wish I’d had at the start, the migration steps that actually held up, and the edge cases that bit us along the way.

First, the thing that confuses everyone

There are two projects with “NGINX Ingress” in the name and they are not the same.

ingress-nginx (the one that died) was the community-maintained controller in kubernetes/ingress-nginx, governed by SIG Network. It’s what helm install ingress-nginx ingress-nginx/ingress-nginx installs. This is what hit end-of-life.

NGINX Ingress Controller (still alive) is F5/NGINX’s commercial-and-OSS product at nginxinc/kubernetes-ingress. Different repo, different annotations (nginx.org/... instead of nginx.ingress.kubernetes.io/...), different release cycle. F5 is happy to sell you a migration path. This product is not retired.

If your manifests have kubernetes.io/ingress.class: nginx and annotations starting with nginx.ingress.kubernetes.io/, you’re on the dead one. If you see nginx.org/ annotations, you’re on F5’s. Half the migration guides floating around blur this line, so before you do anything else: grep your YAML and confirm which one you actually have.

kubectl get ingress -A -o yaml | grep -E 'nginx\.(ingress\.kubernetes\.io|org)/' | sort -u

If the output is the first one, keep reading. If it’s the second, you have more time, and your decision is mostly about whether to stay on the commercial product or migrate anyway.

The deadline math

The dangerous part of an EOL’d controller isn’t day one. It’s the first CVE published against an NGINX or Lua module that ingress-nginx pulls in. There were three of these in 2024 alone. With no maintainer to backport fixes, your options are: fork and patch it yourself, build from a fork someone else patches, or migrate. Forking sounds cheap until you remember you’re now responsible for an NGINX-Lua build pipeline, and most platform teams have neither the appetite nor the headcount.

The “we’ll do it next quarter” plan also assumes you’ll get a clean migration window. You won’t. The day a critical CVE drops is the day everyone in your org is suddenly very interested in your ingress controller, and that’s the worst possible time to be evaluating five replacements. Migrate while you still have the luxury of a calm rollout.

The serious replacements

Five controllers worth comparing. I’m going to be opinionated about which fits which team rather than pretend they’re equivalent.

Traefik v3

The most natural drop-in. Traefik v3 (current as of mid-2026) supports both classic Ingress resources and Gateway API, ships with first-class Let’s Encrypt, and has a UI that platform engineers actually use. Annotations don’t map 1:1 from ingress-nginx, but they’re close enough that a small script gets you 80% of the way there.

Where Traefik shines is mid-sized teams who want something that works out of the box and don’t need bleeding-edge L7 features. Where it doesn’t shine: huge multi-tenant platforms, because the dynamic configuration model gets harder to reason about at scale.

Envoy Gateway

The Gateway-API-native choice. Envoy Gateway is the upstream project that turns Envoy into a Kubernetes-native Gateway API implementation. If you’re going to bite the bullet on Gateway API anyway — and you probably should — this is the path that doesn’t require translating your mental model twice.

Trade-off: it’s younger. The 1.0 release happened in 2024 and the project is moving fast, which means breaking changes show up more often than in Traefik. If you have a platform team that follows upstream Kubernetes development, that’s fine. If your team treats the cluster as a black box and just wants ingress to work, it’s friction.

Kong Ingress Controller

Kong is a real API gateway with rate limiting, JWT auth, OIDC, request transformers, and a plugin ecosystem that goes way beyond what an ingress controller normally does. The Kong Ingress Controller (KIC) v3 supports both Ingress and Gateway API and is the right answer if you were going to bolt an API gateway in front of your ingress eventually anyway.

The downside is operational weight. You’re now running Kong’s data plane, possibly its control plane, and making decisions about Postgres-backed vs DB-less mode. For a team that just wants HTTP routing and TLS termination, this is overkill.

HAProxy Ingress

The performance pick. HAProxy is faster than anything else on this list under brutal load, and HAProxy Ingress is a solid, stable controller. It’s underrated because it doesn’t have the marketing budget of the others. If you’re running a high-RPS workload where every millisecond matters, this is worth a real benchmark.

The ecosystem is smaller. Fewer Grafana dashboards, fewer Stack Overflow answers, fewer Helm-chart examples. You’ll be reading the official docs more than copy-pasting from blog posts.

F5 NGINX Ingress Controller

The commercial path. Same NGINX you already know, supported by F5, with a paid tier that adds WAF, JWT validation, and Active Health Checks. The migration story from ingress-nginx is smooth because the configuration model is similar, just with different annotation prefixes.

The cost question is real. The OSS version is free but feature-limited. The paid version is priced for enterprises, not startups. And no matter which version you pick, you’re now in a vendor relationship with F5, which is a thing some orgs care about and others don’t.

Should you go straight to Gateway API?

This is the question almost every team asks me, and the honest answer is: probably yes, but not today.

Gateway API is the long-term successor to the Ingress resource. It’s better-designed, role-aware (Gateway vs HTTPRoute vs ReferenceGrant), and avoids the annotation-soup mess that made Ingress impossible to reason about. The standard hit GA in 2023, and by 2026 it’s the direction every serious controller is heading.

But here’s the catch: in a stressful, forced migration off a dead controller, you do not want to learn two new things at once. If your team has never written an HTTPRoute, doing a Gateway API rewrite at the same time you’re swapping controllers doubles the surface area for things to break.

My take: migrate to a controller that supports both Ingress and Gateway API (Traefik, Envoy Gateway, Kong, F5 all qualify), keep using Ingress resources during the swap, then plan a separate Gateway API migration after you’ve stabilized. Two small migrations beat one big one.

The exception is greenfield clusters. If you’re standing up a new cluster, skip Ingress entirely and go Gateway-API-only from day one. Envoy Gateway is the cleanest pick for that path.

The phased migration that actually works

Here’s the rollout sequence we used. It’s slow on purpose — the goal is “never break production,” not “fastest possible migration.”

Phase 1: Run both controllers side by side. Install your new controller with a different IngressClass (traefik, envoy, kong, whatever) and leave ingress-nginx alone. Verify the new controller is healthy under no real traffic.

Phase 2: Convert manifests in a parallel namespace. Pick one low-risk service, copy its Ingress YAML, rewrite annotations for the new controller, set the IngressClass to the new one, and apply it. Send synthetic traffic. Diff response headers, latency p99, and TLS behavior against the existing path.

Phase 3: Traffic shift at the DNS or LB layer. This is where teams want to flip the switch all at once and shouldn’t. Use weighted DNS records, or put both controllers behind your cloud LB and weight at that layer. 1% → 10% → 50% → 100% over a week. Watch the SLO dashboards, not your gut.

Phase 4: Cut over and decommission. When 100% of traffic is on the new controller for at least 48 hours and your error budget hasn’t moved, delete the old Ingress resources, then uninstall ingress-nginx. Don’t skip the wait. The most common failure mode I see is uninstalling too fast and discovering some forgotten internal service was still pointed at the old class.

Phase 5: Annotation cleanup. Most automated annotation translators get the 80% case right and silently break the 20% case. Plan a follow-up sprint to manually audit complex rules — rewrites, custom NGINX snippets, mTLS, sticky sessions. Don’t leave this for “later” because “later” never happens.

The edge cases that always bite

These are the things that look fine in staging and break in production. Plan for them up front.

Rewrite rules. nginx.ingress.kubernetes.io/rewrite-target doesn’t map cleanly to most other controllers. Traefik uses Middleware resources, Envoy Gateway uses URLRewrite filters, Kong uses request-transformer plugins. The semantics differ in subtle ways — particularly around capture groups and trailing slashes. Test every rewrite path explicitly.

Custom NGINX snippets. If your team used nginx.ingress.kubernetes.io/configuration-snippet or server-snippet, you’ve been writing raw NGINX config inside annotations. None of that ports automatically. You need to translate each snippet to the new controller’s native config primitive, and some of it (Lua scripts especially) just doesn’t have an equivalent.

Sticky sessions. The cookie-based affinity in ingress-nginx is straightforward. In Traefik you set it on the Service via annotations or via Gateway API’s BackendTLSPolicy-adjacent extensions. In Envoy Gateway, sticky sessions arrived later than basic routing and the semantics differ. Verify with a real load test, not a curl.

mTLS to backends. Backend TLS verification is configured differently in every controller. If your service mesh is doing the heavy lifting (Istio, Linkerd) this matters less. If your ingress controller is terminating client TLS and re-initiating mTLS to backends, you’re going to spend a day getting the cert chain right.

Admission webhooks. ingress-nginx ships a validating webhook that catches bad configs before they’re applied. Most replacements have something similar but the failure modes differ. Make sure your CI/CD applies new manifests to a staging cluster first — don’t trust the webhook to catch everything.

Custom metrics and Grafana dashboards. Your existing dashboards almost certainly key off ingress-nginx Prometheus labels. The metric names differ on every other controller. Budget time to rebuild dashboards, or accept that you’re flying blind for a week.

Which one for which team

If I had to recommend defaults without knowing anything else about your setup, here’s how I’d map it.

  • Small startup, EKS or GKE, want it to just work: Traefik v3. Quickest path, gentlest learning curve, decent UI.
  • Platform team running multi-tenant clusters: Envoy Gateway, with a Gateway API rollout plan. The role separation (Gateway vs HTTPRoute) is what you’ve been wanting without knowing it.
  • You were going to add an API gateway anyway: Kong Ingress Controller. Consolidate now and skip the second migration.
  • High-RPS workload where latency matters more than ergonomics: HAProxy Ingress. Benchmark first.
  • Enterprise with budget, deep NGINX expertise, low risk appetite: F5 NGINX Ingress Controller. Smooth migration, real support contract, money fixes the rest.

The wrong move is to wait. Even if your CVE risk is low this quarter, the ecosystem around ingress-nginx is going to atrophy fast — Helm charts will go stale, Stack Overflow answers will rot, and the next person to onboard your platform team will spend their first week on archaeology. Pick a path now while you can do it calmly.

One concrete thing to try this week: install your candidate replacement on a non-prod cluster, port a single Ingress, and run a load test that mirrors your real traffic shape. You’ll learn more from that one experiment than from a month of reading comparison posts — including this one.