Installing NGINX Open Source Ingress Controller in Kubernetes Using Helm
Overview#
The NGINX Ingress Controller (open source version) is a widely used Kubernetes ingress controller that leverages NGINX as a reverse proxy and load balancer.
This guide walks you through installing it with Helm, following best practices and referencing the official documentation.
Use the latest stable release (e.g., 2.3.1 at the time of writing).
Prerequisites#
- A running Kubernetes cluster (v1.22+ recommended)
- Helm 3 installed (≤ 3.18.4 — avoid 3.18.5 due to an OCI bug)
kubectlconfigured for your cluster- Default setting:
controller.nginxplus=false(open source) - CRDs enabled:
controller.enableCustomResources=true(default)
💡 Notes
- This covers the open-source version (not NGINX Plus).
- Deploy into a dedicated namespace like
nginx-ingress.- The controller runs as a Deployment (1 replica) and exposes a
LoadBalancerservice.
Step 1: Create Namespace#
kubectl create namespace nginx-ingress
Step 2: Install the Helm Chart#
The chart is distributed via the OCI registry, so there’s no need to add a repo.
helm install my-nginx-ingress oci://ghcr.io/nginx/charts/nginx-ingress \
--namespace nginx-ingress \
--version 2.3.1 # Replace with the latest stable version
- Installs CRDs automatically (omit with
--skip-crdsif managing manually) - Customize release name as needed
Manual CRD management example:
helm pull oci://ghcr.io/nginx/charts/nginx-ingress --untar --version 2.3.1
cd nginx-ingress
helm install my-nginx-ingress . --namespace nginx-ingress
Edge build (testing only):
helm install my-nginx-ingress oci://ghcr.io/nginx/charts/nginx-ingress \
--version 0.0.0-edge \
--namespace nginx-ingress
Step 3: Verify Installation#
1. Check pods
kubectl get pods -n nginx-ingress
If pods aren’t ready, ensure CRDs exist:
kubectl get crd | grep ingress
2. Check Service
kubectl get svc -n nginx-ingress
Retrieve external IP for LoadBalancer type:
kubectl get svc my-nginx-ingress-nginx-ingress-controller \
-n nginx-ingress \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}'
For NodePort or ClusterIP, modify with:
--set controller.service.type=NodePort
3. Health check (optional)
curl http://<EXTERNAL-IP>/nginx-health
Expected result: HTTP 200.
Common Customizations#
Use --set flags or a values.yaml file to override defaults.
Watch specific namespaces
--set controller.watchNamespace="default\,nginx-ingress"
Set as default IngressClass
--set controller.ingressClass.setAsDefaultIngress=true
Adjust NGINX log level
--set controller.config.entries.error-log-level=warn
Configure default TLS
--set controller.defaultTLS.secret=nginx-ingress/tls-secret
Or inline (base64):
--set controller.defaultTLS.cert=<base64-cert> \
--set controller.defaultTLS.key=<base64-key>
Resource limits
--set controller.resources.requests.cpu=200m \
--set controller.resources.requests.memory=256Mi
Namespace-scoped RBAC
--set rbac.clusterrole.create=false
To explore all chart parameters:
helm show values oci://ghcr.io/nginx/charts/nginx-ingress --version 2.3.1Or see NGINX Helm parameters.
Post-Installation#
1. Create an Ingress resource
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: default
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
Apply with:
kubectl apply -f ingress.yaml
2. Enable metrics
Prometheus metrics are exposed on port 9113 by default.
3. Upgrade when new version is released
helm upgrade my-nginx-ingress oci://ghcr.io/nginx/charts/nginx-ingress \
--version <new-version> \
--namespace nginx-ingress
⚠️ Avoid toggling
controller.ingressClass.createduring upgrades to prevent accidental resource deletion.
Troubleshooting#
| Issue | Likely Cause | Fix |
|---|---|---|
| Pods not Ready | Missing CRDs | Reinstall without --skip-crds |
| Multiple Instances | CRD version mismatch | Multi-controller setup |
| No TLS Secret | HTTPS fails | Provide default TLS secret |
| General Debug | View logs | kubectl logs -n nginx-ingress deployment/my-nginx-ingress-nginx-ingress-controller |