Skip to content

Ingress NGINX retirement: choose a replacement and test it

Existing routes keep answering once the community controller stops getting fixes. Compare replacements, audit annotations and test before changing DNS.

Published
Topics
KubernetesGateway APIEnvoy
Dark blue cover with the Log'in Line logo and a white title about choosing and testing an Ingress NGINX replacement

The Ingress NGINX retirement ended upstream maintenance in March 2026. Existing deployments keep routing traffic, but the community project no longer provides releases or security fixes. Replace the controller. You can keep the Ingress API with another implementation, or move to Gateway API. Choose by the behavior your applications need, especially authentication and NGINX annotations, rather than by how quickly a converter produces YAML.

For a small team, we recommend evaluating Gateway API first when planning a lasting replacement. Keeping Ingress with a maintained controller is reasonable when the migration must stay narrow. Neither path removes the need to test application traffic.

What stops in March 2026, and what keeps running

The retirement concerns the community kubernetes/ingress-nginx controller. It does not retire NGINX itself, the separate F5 NGINX Ingress Controller, or Kubernetes' Ingress API. The Kubernetes committee statement confirms the March 2026 retirement. An existing load balancer does not stop serving requests because that month has passed.

There is no upstream maintenance window left to plan around. A working deployment can still carry an unpatched component, and upgrading the Kubernetes control plane does not replace an ingress controller installed through your own Helm release.

Check provider-specific support separately. Microsoft states that critical security patches for the AKS application routing add-on's NGINX Ingress resources continue through November 2026. That exception does not cover an arbitrary ingress-nginx installation on AKS. As of November 2, 2026, it is the last stated month, not permission to postpone the project indefinitely. The documentation does not specify a day of the month.

Identify the controller before choosing its replacement

Inventory the controller image and its arguments, the IngressClass, and every application's annotations. A class called nginx is only a name: inspect its controller identifier and the running workload before concluding that it is the retired project.

These read-only examples use the networking.k8s.io/v1 API, kubectl 1.34.1 and jq 1.8.1. The JSON filters and conversion were tested offline on fixtures, not as an end-to-end cluster migration. Cluster queries require cluster-wide read permissions. Use a kubectl version compatible with your server.

kubectl get ingressclasses -o wide
kubectl get deployments,daemonsets -A -o json | jq -r '
  .items[] | . as $w | .spec.template.spec.containers[] |
  [$w.metadata.namespace, $w.metadata.name, .image,
   ((.args // []) | join(" "))] | @tsv'
kubectl get ingress -A -o json > ingress-inventory.json
jq -r '
  .items[] |
  [.metadata.namespace, .metadata.name,
   (.spec.ingressClassName //
    .metadata.annotations["kubernetes.io/ingress.class"] // "unset"),
   ((.metadata.annotations // {} | keys |
     map(select(startswith("nginx.ingress.kubernetes.io/")))) |
     join(","))] | @tsv' ingress-inventory.json

The workload listing deliberately includes all images: it avoids missing a controller mirrored into a private registry. Inspect arguments such as --controller-class and --ingress-class. Also check Helm values and global ConfigMaps for TCP/UDP mappings, proxy settings and snippets. The annotation report cannot see those dependencies.

For each hostname, record the owner, TLS secret, backend protocol and a request that must succeed. Add one request that must be rejected. An authentication migration passes only if an unauthenticated caller still cannot reach the protected backend.

The oversights that cause the most trouble in this kind of move rarely sit in the controller itself. A hand-written authentication annotation on a single Ingress, a TCP mapping left in a global ConfigMap, a rule that no longer matches because its class was not carried over: they tend to surface after cutover, rarely during testing.

Compare maintained Ingress and Gateway API options

Keeping Ingress changes fewer resource types; Gateway API separates infrastructure ownership from application routes. Both still need an installed controller. Gateway API CRDs alone do not create a functioning entry point.

CandidateWhen to evaluate itAcceptance test before choosing
Maintained Ingress controller, such as Traefik or F5 NGINX Ingress ControllerYou need to retain Ingress resources and limit the first migrationCheck every annotation against that controller's documentation; sharing NGINX in a name proves no compatibility
Envoy GatewayYou want a Gateway API entry point built around EnvoyValidate required filters and the controller-specific policies for authentication or rate limiting
KgatewayYou are considering the implementation discussed in our existing Gateway API articleTest the exact version and extensions you intend to run; do not infer feature parity from its proxy
Traefik with Gateway APIYour team already operates Traefik and wants to reuse that knowledgeCheck Gateway API support separately from its Ingress provider and middleware configuration
NGINX Gateway FabricYou prefer a Gateway API implementation using an NGINX data planeVerify the features of the selected edition and release, including any WAF requirement
Cloud-managed entry pointYou prefer delegating controller lifecycle to the cloud providerConfirm regional availability, supported routing features, charges and a way to leave the service

This is a shortlist, not a performance ranking. Pin the controller chart, image and Gateway API CRD versions before testing; do not mix a latest documentation page with an older installed release. A conformance result describes a tested version and feature set. It does not certify support for your NGINX snippets.

For a new HTTP entry point, our proposed default is Gateway API, with Envoy Gateway and Kgateway in the evaluation. Our existing Kgateway article explains that implementation's design. Keep the decision narrower here: a team with simple Ingress rules and a tested maintained replacement may gain little from changing APIs during the same maintenance window.

Treat annotations as application behavior

An annotation has migrated only when the new entry point reproduces its intended behavior. A missing rewrite can return a plausible page from the wrong path; a missing authentication check can expose a private endpoint while every health probe stays green.

Existing dependencyWhat to prove on the candidate
rewrite-target and use-regexCompare the backend path, capture groups and path precedence; regex rules are not automatically portable
auth-url and auth-signinTest denied requests, login redirects, callback URLs and identity headers
proxy-body-size and timeout settingsExercise an upload near the intended limit and a deliberately slow backend
configuration-snippet and server-snippetExplain each directive, then replace its behavior explicitly; arbitrary NGINX directives have no generic Gateway API equivalent
ModSecurity or another WAF dependencyTest the selected engine, rules and enforcement mode; successful routing says nothing about filtering

Start with these dependencies before scoring products. If a required control has no supported replacement, either change the application design or select a different controller. Do not silently drop a security policy to finish the YAML conversion.

Convert offline, then validate a parallel entry point

ingress2gateway generates a starting point for review; it does not prove runtime equivalence. For ingress2gateway v1.2.0, the subcommand is print. The example below was tested offline against that release with an exported Ingress fixture. It does not install a controller or apply anything to the cluster.

ingress2gateway version
ingress2gateway print --providers=ingress-nginx \
  --input-file=ingress-inventory.json \
  --ingress-nginx-ingress-class=nginx \
  --all-namespaces > gateway-candidate.yaml

Replace nginx with the source class from your inventory. Review the output's gatewayClassName against your installed target GatewayClass before applying anything. Save stderr diagnostics: our fixture produced YAML while warning that configuration-snippet was unsupported and proxy-body-size could not be applied by the standard emitter. Command success does not mean equivalent behavior. Review secrets, namespace boundaries and target-specific policies too.

Deploy the candidate with a separate address and explicit class selection. Check that neither controller claims the other's routes, and keep automated DNS tooling from publishing the candidate prematurely. Test its real TLS certificate and hostname before changing public DNS. With an IPv4 address, curl can direct a request to the candidate while preserving SNI and the HTTP host:

HOST=app.example.com
CANDIDATE_IP=203.0.113.20
curl --fail-with-body --resolve "${HOST}:443:${CANDIDATE_IP}" \
  "https://${HOST}/health"

Those values are placeholders. Do not add -k: bypassing certificate validation would hide a failed TLS migration. A health endpoint checks only one path. Replay the protected requests, uploads, redirects and long-lived connections from your acceptance list. Inspect backend logs as well as HTTP status codes.

Schema: test a separate candidate address before moving public DNS

Move one hostname first. Define your own error-rate and latency thresholds from its baseline, then watch both entry points during DNS propagation. Keep the old configuration and certificates available for an agreed rollback period. Returning DNS to the previous address does not move cached clients or existing connections immediately. The retired controller is a temporary fallback, not a long-term recovery plan.

Budget the migration around exceptions, not route count

The work comes from distinct routing behaviors and their tests. Estimate inventory and annotation review, policy rewrites, parallel infrastructure, application testing, the cutover and the rollback rehearsal separately. There is no defensible universal number of days per cluster.

Record the duplicate load balancer and proxy capacity for the overlap period. Compute that cost from your provider's current hourly rates and the measured duration; add any edition or support subscription required for authentication or WAF features. Do not compare a free controller with a managed offer while excluding those dependencies.

Our recommendation: remove the unsupported controller first, with a named owner and a tested fallback. Gateway API is the preferred evaluation path for a lasting redesign; retained Ingress is a valid smaller change. If nobody owns the inventory or the cutover, our Kubernetes managed services can take over the operational work. Bring your controller image and annotation export to a free 30-minute diagnostic.

About the author

The Log’in Line team

Get a full team for the price of a part-time freelancer.

Contact us
infra@loginline.com
No commitmentOn-call included