How to Configure NGINX Ingress with TLS using cert-manager
Learn how to set up NGINX Ingress Controller with automatic TLS certificates from Let's Encrypt using cert-manager. Complete YAML examples and troubleshooting tips included.
The Problem
You want to expose your Kubernetes services over HTTPS with valid TLS certificates, but managing certificates manually is error-prone and doesn’t scale.
The Solution
Use NGINX Ingress Controller combined with cert-manager to automatically provision and renew TLS certificates from Let’s Encrypt.
Step 1: Install NGINX Ingress Controller
First, add the ingress-nginx Helm repository and install the controller:
# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# Install NGINX Ingress Controller
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.publishService.enabled=trueVerify the installation:
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginxStep 2: Install cert-manager
Install cert-manager to handle automatic certificate management:
# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io
helm repo update
# Install cert-manager with CRDs
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=trueWait for cert-manager pods to be ready:
kubectl get pods -n cert-managerStep 3: Create a ClusterIssuer
Create a ClusterIssuer for Let’s Encrypt. Save this as cluster-issuer.yaml:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your-email@example.com
# Name of secret to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginxApply it:
kubectl apply -f cluster-issuer.yamlTip: For testing, use
https://acme-staging-v02.api.letsencrypt.org/directoryto avoid rate limits.
Step 4: Create an Ingress with TLS
Now create an Ingress resource that uses the ClusterIssuer. Save as my-app-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
# Use the letsencrypt-prod ClusterIssuer
cert-manager.io/cluster-issuer: "letsencrypt-prod"
# Force HTTPS redirect
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls # cert-manager will create this
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80Apply the Ingress:
kubectl apply -f my-app-ingress.yamlStep 5: Verify Certificate Issuance
Check the certificate status:
# Check Certificate resource
kubectl get certificate
# Check certificate details
kubectl describe certificate myapp-tls
# Check the secret was created
kubectl get secret myapp-tlsThe certificate should transition from False to True within 1-2 minutes.
Common Issues
Certificate stuck in “False” state
Check the Certificate and CertificateRequest status:
kubectl describe certificate myapp-tls
kubectl get certificaterequest
kubectl describe certificaterequest <name>HTTP-01 challenge failing
Ensure your domain resolves to the Ingress controller’s external IP:
# Get the external IP
kubectl get svc -n ingress-nginx
# Test DNS resolution
nslookup myapp.example.comRate limiting
Let’s Encrypt has rate limits. Use the staging server for testing:
server: https://acme-staging-v02.api.letsencrypt.org/directoryComplete Example
Here’s a complete example with a sample deployment:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80Summary
You’ve learned how to:
- Install NGINX Ingress Controller using Helm
- Install cert-manager for automatic certificate management
- Create a ClusterIssuer for Let’s Encrypt
- Configure an Ingress with automatic TLS
Certificates will be automatically renewed by cert-manager before they expire.
References
📘 Go Further with Kubernetes Recipes
Love this recipe? There’s so much more! This is just one of 100+ hands-on recipes in our comprehensive Kubernetes Recipes book.
Inside the book, you’ll master:
- ✅ Production-ready deployment strategies
- ✅ Advanced networking and security patterns
- ✅ Observability, monitoring, and troubleshooting
- ✅ Real-world best practices from industry experts
“The practical, recipe-based approach made complex Kubernetes concepts finally click for me.”
👉 Get Your Copy Now — Start building production-grade Kubernetes skills today!
📘 Get All 100+ Recipes in One Book
Stop searching — get every production-ready pattern with detailed explanations, best practices, and copy-paste YAML.
Want More Kubernetes Recipes?
This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.