See the prerequisites
This deployment is for NGINX Ingress Controller and F5 WAF for NGINX without precompiled WAF policies
- Create NGINX Ingress Controller namespace
kubectl create namespace nginx-ingress
- Create Kubernetes secret to pull images from NGINX private registry
kubectl create secret docker-registry regcred --docker-server=private-registry.nginx.com --docker-username=`cat <nginx-one-eval.jwt>` --docker-password=none -n nginx-ingress
Note: <nginx-one-eval.jwt> is the path and filename of your nginx-one-eval.jwt file
- Create Kubernetes secret holding the NGINX Plus license
kubectl create secret generic license-token --from-file=license.jwt=<nginx-one-eval.jwt> --type=nginx.com/license -n nginx-ingress
Note: <nginx-one-eval.jwt> is the path and filename of your nginx-one-eval.jwt file
- List available NGINX Ingress Controller docker images that include NGINX App Protect WAF
curl -s https://private-registry.nginx.com/v2/nginx-ic-nap/nginx-plus-ingress/tags/list --key <nginx-one-eval.key> --cert <nginx-one-eval.crt> | jq
Note: <nginx-one-eval.key> and <nginx-one-eval.key> are the path and filename of your nginx-one-eval.crt and nginx-one-eval.crt files respectively
Pick the latest version (5.4.1 at the time of writing)
- Apply NGINX Ingress Controller custom resources (make sure the URI below references the latest available
5.xNGINX Ingress Controller version)
kubectl apply -f https://raw.githubusercontent.com/nginx/kubernetes-ingress/v5.4.1/deploy/crds.yaml
kubectl apply -f https://raw.githubusercontent.com/nginx/kubernetes-ingress/v5.4.1/deploy/crds-nap-waf.yaml
- Install NGINX Ingress Controller with NGINX App Protect through its Helm chart (set
nginx.image.tagto the latest5.xavailable NGINX Ingress Controller version)
helm install nic oci://ghcr.io/nginx/charts/nginx-ingress \
--version 2.5.1 \
--set controller.image.repository=private-registry.nginx.com/nginx-ic-nap/nginx-plus-ingress \
--set controller.image.tag=5.4.1 \
--set controller.nginxplus=true \
--set controller.appprotect.enable=true \
--set controller.serviceAccount.imagePullSecretName=regcred \
--set controller.mgmt.licenseTokenSecretName=license-token \
--set controller.service.type=NodePort \
-n nginx-ingress
- Check NGINX Ingress Controller pod status
kubectl get pods -n nginx-ingress
Pod should be in the Running state
NAME READY STATUS RESTARTS AGE
nic-nginx-ingress-controller-7575f4d76f-888v7 1/1 Running 0 62s
- Check NGINX Ingress Controller logs
kubectl logs -l app.kubernetes.io/instance=nic -n nginx-ingress -c nginx-ingress
Output should be similar to
I20260409 15:57:09.501899 1 main.go:112] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"nginx-ingress", Name:"nic-nginx-ingress", UID:"72830f00-d69c-400c-9f11-611df7a9b418", APIVersion:"v1", ResourceVersion:"108817766", FieldPath:""}): type: 'Normal' reason: 'Updated' ConfigMap nginx-ingress/nic-nginx-ingress updated without error
I20260409 15:57:09.501926 1 main.go:112] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"nginx-ingress", Name:"nic-nginx-ingress-mgmt", UID:"4bfd2675-012e-43cb-a7a2-2aa57da79561", APIVersion:"v1", ResourceVersion:"108817764", FieldPath:""}): type: 'Normal' reason: 'Updated' MGMT ConfigMap nginx-ingress/nic-nginx-ingress-mgmt updated without error
2026/04/09 15:57:09 [notice] 15#15: signal 17 (SIGCHLD) received from 20
2026/04/09 15:57:09 [notice] 15#15: worker process 20 exited with code 0
2026/04/09 15:57:09 [notice] 15#15: signal 29 (SIGIO) received
2026/04/09 15:57:09 [notice] 15#15: signal 17 (SIGCHLD) received from 21
2026/04/09 15:57:09 [notice] 15#15: worker process 21 exited with code 0
2026/04/09 15:57:09 [notice] 15#15: signal 29 (SIGIO) received
BD_MISC|NOTICE|Apr 09 15:57:25.411|0036|/builds/t1_xXBa_N/12/waf/waf-general/secore/bd/bd/temp_func.c:2874|UMU: 0 0 || 0 0 0 0 0 0 0 0 0 0 0 0 || 0 0 0 0 0 0 0
BD_MISC|NOTICE|Apr 09 15:57:25.411|0036|/builds/t1_xXBa_N/12/waf/waf-general/secore/bd/bd/temp_func.c:2875|UMU: total 0 ( 0Kb) VM (486M) RSS ( 49M) SWAP ( 0M) Cache (0) trans 0
- Check Kubernetes service status
kubectl get svc -n nginx-ingress
NGINX Ingress Controller should be listening on TCP ports 80 and 443
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nic-nginx-ingress-controller NodePort 10.109.220.151 <none> 80:31233/TCP,443:31404/TCP 86s
- Check the
ingressclass
kubectl get ingressclass
The nginx ingressclass should be available
NAME CONTROLLER PARAMETERS AGE
nginx nginx.org/ingress-controller <none> 101s
- Uninstall NGINX Ingress Controller through its Helm chart
helm uninstall nic -n nginx-ingress
- Delete the namespace
kubectl delete namespace nginx-ingress
- Delete custom resources
kubectl delete -f https://raw.githubusercontent.com/nginx/kubernetes-ingress/v5.4.1/deploy/crds.yaml
kubectl delete -f https://raw.githubusercontent.com/nginx/kubernetes-ingress/v5.4.1/deploy/crds-nap-waf.yaml