DEV Community

Hamdi KHELIL
Hamdi KHELIL

Posted on

Using Nginx Ingress Controller and Cert-Manager for HTTPS with Let’s Encrypt ⚡

Hey there! In today’s world, serving your web apps over HTTPS is a must. Luckily, combining the power of Nginx Ingress Controller with Cert-Manager helps you easily request, issue, and renew TLS certificates from Let’s Encrypt. In this friendly guide, we’ll walk you through:

  1. Installing the Nginx Ingress Controller
  2. Installing Cert-Manager
  3. Creating a ClusterIssuer to fetch certificates from Let’s Encrypt
  4. Configuring an example Ingress to serve traffic via HTTPS

Let’s get started! 🚀

Prerequisites

  • A running Kubernetes cluster (any flavor you like—Minikube, managed cloud, etc.)
  • kubectl installed and configured to connect to your cluster
  • A domain you control, where you can edit DNS records to point to your cluster’s Ingress IP

Step 1: Install Nginx Ingress Controller

The Nginx Ingress Controller routes external requests to services in your cluster. One easy way to install is using Helm:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx --create-namespace 
Enter fullscreen mode Exit fullscreen mode

After installation, confirm everything is up and running:

kubectl get pods -n ingress-nginx kubectl get svc -n ingress-nginx 
Enter fullscreen mode Exit fullscreen mode
  • If you see a LoadBalancer service, note its external IP. You’ll point your domain’s DNS record to that IP.
  • If using Minikube or a NodePort setup, you’ll need to retrieve the node IP or the port mapping.

Step 2: Install Cert-Manager

Cert-Manager automates certificate lifecycle management. Again, Helm makes it simple:

helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager --create-namespace \ --version v1.14.1 \ --set installCRDs=true 
Enter fullscreen mode Exit fullscreen mode

You should see three pods in the cert-manager namespace:

  • cert-manager
  • cert-manager-cainjector
  • cert-manager-webhook

All should be in a Running state.

Step 3: Create a ClusterIssuer for Let’s Encrypt

Next, create a ClusterIssuer to handle certificate requests for your entire cluster. Below is an example using Let’s Encrypt’s staging environment (less risk of rate-limit issues):

apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: youremail@example.com privateKeySecretRef: name: letsencrypt-staging-account-key solvers: - http01: ingress: class: nginx 
Enter fullscreen mode Exit fullscreen mode

Apply it:

kubectl apply -f letsencrypt-staging.yaml 
Enter fullscreen mode Exit fullscreen mode

Once you test successfully, switch to production by using https://acme-v02.api.letsencrypt.org/directory in the server field and a new secret name. For instance:

apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-production spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: youremail@example.com privateKeySecretRef: name: letsencrypt-prod-account-key solvers: - http01: ingress: class: nginx 
Enter fullscreen mode Exit fullscreen mode

Apply it with:

kubectl apply -f letsencrypt-production.yaml 
Enter fullscreen mode Exit fullscreen mode

You’ll now have both a staging and a production ClusterIssuer.

Step 4: Deploy an Example Application

Let’s deploy a simple “Hello World” app on Nginx:

kubectl create namespace demo kubectl create deployment hello-world --image=nginx -n demo kubectl expose deployment hello-world --port=80 --type=ClusterIP -n demo 
Enter fullscreen mode Exit fullscreen mode

This deployment and service will run your test web page on port 80 inside the demo namespace.

Step 5: Create the Ingress Resource

Now let’s define an Ingress that:

  1. Routes HTTP traffic from example.com to your hello-world service
  2. Requests a TLS certificate from Let’s Encrypt via Cert-Manager
  3. Forces HTTPS (using an Nginx annotation)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: hello-world-ingress namespace: demo annotations: cert-manager.io/cluster-issuer: "letsencrypt-production" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" spec: ingressClassName: nginx tls: - hosts: - example.com secretName: hello-world-tls rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: hello-world port: number: 80 
Enter fullscreen mode Exit fullscreen mode

Apply it:

kubectl apply -f hello-world-ingress.yaml 
Enter fullscreen mode Exit fullscreen mode

Replace example.com with your actual domain.

Additional Example: Multiple Hosts

If you have multiple domains, you can define more rules and tls entries. For example:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: multi-host-ingress namespace: demo annotations: cert-manager.io/cluster-issuer: "letsencrypt-production" spec: ingressClassName: nginx tls: - hosts: - app1.example.com secretName: app1-tls - hosts: - app2.example.com secretName: app2-tls rules: - host: app1.example.com http: paths: - path: / pathType: Prefix backend: service: name: hello-world port: number: 80 - host: app2.example.com http: paths: - path: / pathType: Prefix backend: service: name: hello-world port: number: 80 
Enter fullscreen mode Exit fullscreen mode

Each domain (app1.example.com and app2.example.com) will get its own certificate and secret.

Step 6: Update Your DNS

Point your domain (example.com) to the external IP of the Nginx Ingress Controller. This is typically done by creating or updating an A record in your DNS provider. If you have multiple hosts (like app1.example.com, app2.example.com), create A records for each one pointing to the same Ingress IP.

Step 7: Verify

  1. Check the Ingress:
 kubectl describe ingress hello-world-ingress -n demo 
Enter fullscreen mode Exit fullscreen mode

Confirm the domain, service mapping, and annotations are correct.

  1. Check Cert-Manager logs:
 kubectl logs -n cert-manager deploy/cert-manager 
Enter fullscreen mode Exit fullscreen mode

Look for messages about the certificate being successfully issued.

  1. Test in the browser:
    Visit https://example.com. If everything went smoothly, you’ll see the default Nginx page over a secure connection! 🔒

  2. Check the certificate:
    In your browser, click the padlock icon or check dev tools to ensure it’s signed by Let’s Encrypt.

Automatic Renewal

Cert-Manager handles certificate renewals automatically, so you won’t need to worry about expiring certificates. It checks each certificate’s expiration date and renews as needed, keeping your sites secure without any hassle. 🙌

Troubleshooting Tips

  • HTTP challenge fails?

    Make sure DNS is pointing to your Ingress IP. If Let’s Encrypt can’t reach your domain, the challenge will fail.

  • Wrong Ingress class?

    Double-check ingressClassName: nginx (or whatever your Nginx Ingress Controller is using).

  • Rate limits

    Use staging mode (like letsencrypt-staging) for your initial tests to avoid hitting production rate limits. Switch to production only once you’ve verified everything.

  • Logs & events

    Check logs with:

 kubectl describe certificate <certificate-name> kubectl describe challenge <challenge-name> 
Enter fullscreen mode Exit fullscreen mode

These commands can show detailed errors on why a certificate request might fail.

Conclusion

Congrats! 🎉 You’ve successfully deployed Nginx Ingress Controller with Cert-Manager and Let’s Encrypt on your Kubernetes cluster. This setup not only secures traffic but also takes care of automatic certificate issuance and renewal—so you can focus on building awesome applications.

Happy clustering ! ✨

Top comments (0)