1. The Inflection Point: Why Migration Can No Longer Wait
For years, the Kubernetes community-maintained ingress-nginx controller served as the default entry point for HTTP traffic into Kubernetes clusters. At its peak, it was estimated to be deployed in more than 40% of Kubernetes clusters, accumulating over 10 million Docker Hub downloads. However, on March 24, 2026, the project was officially archived. Version 1.15.1 was its final release. No further security patches, bug fixes, or feature development will follow.
This was not an overnight decision. For years the project operated on thin maintenance — largely sustained by one or two engineers working outside business hours. The situation became critical in early 2025 when CVE-2025-1974, commonly known as IngressNightmare, was disclosed with a CVSS score of 9.8. This critical remote code execution vulnerability, capable of enabling full cluster takeover, underscored just how high the stakes are for unmaintained ingress infrastructure.
The practical consequence is clear: clusters still running ingress-nginx are now accumulating unpatched CVEs with no remediation path. For organizations in regulated sectors — financial services, insurance, or telecommunications — operating with end-of-life infrastructure is not merely a technical concern but a compliance and governance risk.
2. Understanding the F5 NGINX Ingress Controller
The F5 NGINX Ingress Controller (nginx/kubernetes-ingress) is a Kubernetes-native Ingress implementation built and maintained directly by the NGINX engineering team at F5. It supports both NGINX Open Source and NGINX Plus as its data plane and is available in two tiers:
- NGINX Ingress Controller (OSS) — Apache 2.0 licensed, open source, with advanced traffic management, VirtualServer CRDs, TLS termination, TCP/UDP load balancing, Prometheus metrics, and OpenTelemetry support.
- NGINX Plus Ingress Controller — The enterprise tier built on NGINX Plus, adding dynamic reconfiguration without worker process reloads, active health checks, the NGINX Plus live activity monitoring dashboard, NGINX App Protect WAF, and vendor commercial support with SLAs.
A key differentiator from the community controller is that F5 develops and maintains both the load balancer engine (NGINX/NGINX Plus) and the controller application itself. This unified ownership model means that the ingress layer benefits from native NGINX capabilities — with significantly less dependency on Lua-driven extension behavior compared with the community ingress-nginx controller, reducing the associated memory leak and OOM crash risks.
2.1 Why NGINX Plus Matters for Enterprise Deployments
The Open Source tier of NGINX Ingress Controller is production-capable for many use cases. However, in enterprise environments — particularly those governed by SLAs, zero-downtime mandates, or security compliance frameworks — NGINX Plus unlocks a qualitatively different operational posture:
3. Architectural Shift: From Annotations to CRDs
The most significant conceptual change when moving to the F5 NGINX Ingress Controller is the configuration philosophy. The community ingress-nginx controller was annotation-driven. Complex behaviors — rewrite rules, canary weights, rate limits, authentication — were expressed as opaque key-value string annotations on standard Kubernetes Ingress resources. This approach, while flexible, had serious drawbacks: no schema validation, no IDE autocompletion, and brittle Lua-based extensions that could introduce memory leaks and out-of-memory crashes.
The F5 NGINX Ingress Controller is CRD-native. Its primary configuration model uses Custom Resource Definitions that are schema-validated by the Kubernetes API server at apply time — misconfigured resources are rejected before they ever reach NGINX. The five core CRDs are:
For teams that need a phased migration approach, the F5 controller also supports standard Kubernetes Ingress resources with its own annotation syntax (nginx.org/* prefix, distinct from ingress-nginx’s nginx.ingress.kubernetes.io/* prefix). This means you can initially migrate the controller without rewriting every Ingress manifest, then progressively adopt CRDs where advanced behavior is needed.
4. Before You Migrate: Audit and Inventory
A successful migration begins with a thorough audit of the current state. Ingress migrations that fail typically do so because teams discover undocumented annotation usage mid-migration. The inventory phase is non-negotiable.
4.1 Identify Existing Controller and Resources
First, confirm you are running the community ingress-nginx controller:
kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginxThen enumerate all Ingress resources cluster-wide:
kubectl get ingress --all-namespaces -o yaml > ingress-inventory.yamlExtract all unique annotations in use across your Ingress resources:
kubectl get ingress --all-namespaces -o json | \
jq -r '.items[].metadata.annotations | keys[]' | sort -u4.2 Classify Your Annotations
Once you have the full annotation inventory, classify each annotation into one of three migration categories:
4.3 Document Global ConfigMap Settings
The community controller uses a ConfigMap for global NGINX settings. Document all keys in use and map them to their NGINX Ingress Controller ConfigMap equivalents — the key names often differ. The official migration guide at docs.nginx.com provides a complete ConfigMap key translation table.
4.4 Define Goals and Success Criteria
Before executing the migration, define measurable success criteria:
- Minimal or near-zero production downtime during the cutover window
- All existing routing rules, TLS terminations, and backend health checks functioning identically
- Security policies (WAF, rate limiting, mTLS) migrated and validated
- Prometheus metrics and alerting dashboards updated for the new controller
- Old controller fully decommissioned within an agreed timeframe
5. The Phased Migration Plan
Attempting a big-bang migration of a production Ingress controller is high-risk and unnecessary. Both controllers can run concurrently in the same cluster using separate IngressClass resources, enabling a controlled, service-by-service migration with real-time validation at each step.
01 Parallel Deploy
- Install NGINX Ingress Controller in a separate namespace (e.g., nginx-ingress) using Helm
- Register a distinct IngressClass (e.g., nginx-nic) so the new controller manages no resources yet
- For NGINX Plus: pull the controller image from the F5 Container Registry using your JWT license key
- Validate the new controller is running and healthy — it should process zero Ingress resources at this stage
- Install CRDs: VirtualServer, VirtualServerRoute, Policy, TransportServer, GlobalConfiguration
02 Configure & Convert
- Select a low-risk, non-critical service as the first migration target
- Author a VirtualServer (or annotated Ingress) equivalent of the existing Ingress manifest
- Convert annotations using the NGINX Ingress Migration Tool at kubernetes.nginx.org — paste your YAML, get migration suggestions with 130+ annotation mappings
- For Policy CRDs (rate limiting, mTLS, JWT): author Policy resources and attach via nginx.org/policies annotation
- For TCP/UDP services: replace ConfigMap-based exposure with TransportServer + GlobalConfiguration CRDs
- Ensure TLS secrets are present in the same namespace as the VirtualServer or Ingress resource
03 Test & Validate
- Set ingressClassName to nginx-nic on the migrated resource — it is now managed by the new controller
- Run functional tests: routing correctness, TLS termination, header manipulation, error pages
- Run security tests: WAF policy enforcement, rate limiting, mTLS handshake validation
- Check Prometheus metrics endpoint on the new controller and validate dashboards
- For NGINX Plus: verify live activity monitoring dashboard shows accurate upstream health
- Confirm cert-manager integration: if using VirtualServer CRDs, retain a minimal ‘shim’ Ingress for HTTP-01 ACME challenge or switch to DNS-01 validation
04 Traffic Cutover
- Use VirtualServer traffic splitting (VirtualServer.Route.Splits) to shift traffic by weight — e.g., 90% old controller, 10% new — for gradual validation with real user traffic
- Monitor latency, error rates, and upstream health throughout the shift using observability tooling
- Progressively increase traffic weight to the new controller (50/50, then 90/10, then 100/0)
- If issues are detected, shift traffic back immediately — both controllers remain live throughout
- Once 100% traffic is on the new controller, monitor for a stability window (typically 2–7 days) before decommission
05 Decommission
- Once all services are migrated and validated at 100% traffic, remove the old ingress-nginx Deployment and DaemonSet
- Delete the old IngressClass resource (ingressClassName: nginx)
- Remove unused ConfigMaps that held ingress-nginx global configuration
- Clean up any legacy namespace and RBAC artifacts from the community controller
- Update internal documentation, runbooks, and CI/CD pipelines to reference the new controller
6. Common Annotation-to-CRD Conversions
The following are the most commonly encountered annotation translations. The complete 130+ annotation mapping reference is available at kubernetes.nginx.org/ingress-nginx-migration.html.
6.1 Path Rewriting
Before (ingress-nginx):
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
...
path: /api(/|$)(.*)
After (VirtualServer):
routes:
- path: ~/api(/|$)(.*)
action:
proxy:
upstream: api-svc
rewritePath: /$2
6.2 Canary / Blue-Green Deployments
Before (ingress-nginx):
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
After (VirtualServer with traffic splitting):
routes:
- path: /
splits:
- weight: 80
action:
pass: app-stable
- weight: 20
action:
pass: app-canary
6.3 Rate Limiting
Before (ingress-nginx):
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-connections: "5"
After (Policy CRD + VirtualServer or Ingress reference):
# Policy resource
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: rate-limit-policy
spec:
rateLimit:
rate: 10r/s
burst: 20
zoneSize: 10m
key: ${binary_remote_addr}
# Attach to Ingress (v5.4.0+)
annotations:
nginx.org/policies: rate-limit-policy
6.4 mTLS Client Certificate Authentication
Before (ingress-nginx):
annotations:
nginx.ingress.kubernetes.io/auth-tls-secret: default/ca-secret
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
After (Policy CRD):
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: mtls-policy
spec:
ingressMTLS:
clientCertSecret: ca-secret
verifyClient: "on"
verifyDepth: 2
7. Special Cases and Known Challenges
7.1 cert-manager with VirtualServer CRDs
cert-manager’s HTTP-01 ACME solver requires a standard Kubernetes Ingress resource to serve the challenge token. When migrating to VirtualServer CRDs, a common and well-proven pattern is retaining a minimal ‘shim’ Ingress resource with cert-manager annotations solely for certificate issuance, while all routing configuration moves to VirtualServer. Alternatively, DNS-01 challenge validation can be used to eliminate this dependency entirely.
7.2 Long-Lived Connections (WebSocket, gRPC)
WebSocket and gRPC connections that are active during a controller reload or transition may be terminated. With NGINX Plus, the dynamic reconfiguration API eliminates reload events for upstream changes, significantly reducing this risk. For the OSS tier, schedule traffic cutover during low-traffic windows and use connection draining to allow in-flight requests to complete.
7.3 TCP/UDP Service Exposure
The community controller exposed TCP/UDP services via a dedicated ConfigMap. The F5 controller replaces this with the TransportServer CRD, which offers a structured schema, per-listener timeout configuration, health checks, and TLS Passthrough. GlobalConfiguration registers the cluster-wide TCP/UDP listeners that TransportServer resources reference.
7.4 Custom Lua Extensions in ingress-nginx
Some advanced ingress-nginx behaviors were implemented via custom Lua extensions — particularly for complex load balancing algorithms and sticky session logic. These have no direct equivalent and must be re-implemented using NGINX Ingress Controller’s native capabilities: the Policy CRD for session persistence (sticky cookies are now available in the OSS tier as of v5.4.0), or custom NGINX configuration snippets for lower-level behaviors. It is worth noting that the removal of Lua also eliminates the associated memory leak and OOM crash risks.
8. Post-Migration Validation Checklist
Before decommissioning the old controller, validate each of the following:
9. The Road Ahead: NGINX Gateway Fabric and the Gateway API
The F5 NGINX Ingress Controller is the pragmatic migration target for today — it provides the lowest friction path away from ingress-nginx while delivering enterprise-grade capabilities. However, the Kubernetes ecosystem is actively evolving toward the Gateway API as the next-generation standard for traffic management.
The Gateway API addresses fundamental limitations of the Ingress API: role-based access control across infrastructure owners, namespace owners, and application developers; multi-protocol support as a first-class concern; and extensibility through a well-defined object model rather than annotation proliferation.
F5 NGINX’s answer to the Gateway API is NGINX Gateway Fabric — a fully conformant implementation of the Kubernetes Gateway API with control and data plane separation, multi-cloud support, traffic splitting, and mTLS. For teams migrating today, NGINX Ingress Controller provides a stable operating foundation while Gateway Fabric matures. F5 provides the ingress2gateway CLI tool to automate conversion of Ingress resources to Gateway API HTTPRoute manifests when the time comes.
10. Conclusion
The end-of-maintenance of the community ingress-nginx controller is a forcing function, not just a lifecycle event. Organizations that act now — with a structured, phased migration plan — will not only eliminate security exposure but emerge with a more capable, maintainable, and future-proof Kubernetes networking layer.
The F5 NGINX Ingress Controller offers a genuinely low-friction migration path. Built on the same NGINX foundation, with a more structured and supportable Kubernetes control plane, a dedicated full-time engineering team, a published CVE lifecycle, structured CRD-based configuration, and a clear roadmap toward the Kubernetes Gateway API. For enterprises that need the full spectrum of capabilities — App Protect WAF, dynamic reconfiguration, active health checks, and commercial SLAs — NGINX Plus integration delivers a production-hardened ingress layer built for mission-critical workloads.
At Ashnik, as an authorized F5 NGINX partner operating across India and Southeast Asia, we have worked with organizations across the BFSI, telecom, and insurance sectors through Kubernetes infrastructure modernization initiatives. Our teams have hands-on experience designing and executing ingress migrations, including complex multi-tenant deployments, air-gapped cluster environments, and observability-integrated ingress architectures. We are well-positioned to help your organization plan and execute this migration — from initial audit through production cutover.