Skip to content

Installing Let’s Encrypt in Kubernetes with Ingress

If you’re exposing services to the internet through Kubernetes, securing them with HTTPS is essential. Luckily, you don’t need to manually manage SSL certificates anymore – with Let’s Encrypt and cert-manager, TLS certificates can be issued and renewed automatically.

In this post, we’ll walk you through securing your Kubernetes Ingress using Let’s Encrypt in production, without staging steps.

Prerequisites

Before starting, make sure you have:

  • A working Kubernetes cluster
  • A domain name (e.g. app.example.com)
  • DNS A/AAAA records pointing to your Ingress controller
  • An Ingress controller like NGINX installed and configured

Step 1: Install cert-manager

We’ll install cert-manager using Helm with CRDs included.

helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set installCRDs=true

Verify the pods:

kubectl get pods -n cert-manager

Wait until all the cert-manager pods are running.

Step 2: Create a ClusterIssuer for Let’s Encrypt Production

Now we’ll set up a ClusterIssuer that tells cert-manager to use Let’s Encrypt’s production environment to issue certificates.

Create a file called clusterissuer-prod.yaml:

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

Replace your-email@example.com with your real email. This is important for recovery and expiration notices.

Apply it:

kubectl apply -f clusterissuer-prod.yaml

Step 3: Create a TLS-Enabled Ingress Resource

Now we’ll define an Ingress that:

  • Uses the letsencrypt-prod ClusterIssuer
  • Automatically generates and attaches a TLS certificate

Create a file myapp-ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - app.example.com
      secretName: myapp-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: myapp-service
                port:
                  number: 80

Replace app.example.com and myapp-service with your actual domain and service.

Apply it:

kubectl apply -f myapp-ingress.yaml

cert-manager will detect the annotation and automatically request a certificate from Let’s Encrypt. The certificate will be saved to the Secret myapp-tls.

Verify Certificate Issuance

Check the certificate:

kubectl describe certificate myapp-tls

Check the Ingress:

kubectl get ingress myapp-ingress

Visit your domain in the browser: https://app.example.com
You should see a valid Let’s Encrypt certificate in use.

Auto-Renewal and Maintenance

cert-manager monitors certificate expiration and will renew automatically 30 days before expiry.

To check certificate status:

kubectl get certificate --all-namespaces

To check logs:

kubectl logs -n cert-manager -l app.kubernetes.io/name=cert-manager --follow

With cert-manager and Let’s Encrypt, securing your Kubernetes workloads with HTTPS has never been easier. In just a few manifests, you can enable automatic TLS that renews itself with no human intervention – the way SSL should be.

Troubleshooting

If you encounter this error while applying your Ingress:

Error: admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: host "abc" and path "/" is already defined in ingress

This means another Ingress resource in your cluster is already using the same host and path combination.

Solution 1: Remove the webhook (quick fix)

You can delete the webhook that enforces this validation:

kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

Warning: This disables important safety checks for NGINX Ingress. Use with caution.

Solution 2: Upgrade NGINX Ingress Controller

This issue might be related to bugs in older versions of the NGINX Ingress controller. Consider upgrading to the latest stable version.

helm repo update
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --set controller.image.tag=<latest-version>

Replace <latest-version> with the latest available tag from the official chart.

Resources

Published inAutomationKubernetesLinux