Skip to content

How to Set Up cert-manager in Kubernetes

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about How to Set Up cert. We cover key concepts, practical examples, and best practices.

The Problem

Your cert-manager Certificate resource stays in Ready: False status, the Issuer is not found, or the TLS secret is never created. Ingress resources that reference the secret show TLS handshake error because the certificate does not exist.

Quick Fix

Fix 1: Certificate Not Ready

kubectl get certificate
# NAME              READY   SECRET           AGE
# example-tls       False   example-tls      5m

kubectl describe certificate example-tls
# Status:
#   Conditions:
#     Reason:  IssuerNotReady
#     Message: Issuer letsencrypt-prod is not ready

RIGHT β€” check the Issuer:

kubectl describe issuer letsencrypt-prod
# Status:
#   Conditions:
#     Reason:  ACMEAccountRegistrationFailed
#     Message: Failed to register ACME account: 429 Too Many Requests

Wait and retry, or check the issuer configuration.

Fix 2: ACME Issuer Configuration

WRONG β€” ClusterIssuer without proper ACME settings:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-account-key
    # missing solvers

RIGHT β€” complete ClusterIssuer with solvers:

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

Fix 3: Certificate DNS Names Mismatch

WRONG β€” certificate name does not match the Ingress host:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-tls
spec:
  secretName: example-tls
  dnsNames:
  - app.example.com    # certificate is for app.example.com
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  tls:
  - hosts:
    - www.example.com   # ingress uses www.example.com
    secretName: example-tls

RIGHT β€” match DNS names:

spec:
  dnsNames:
  - www.example.com    # must match the ingress host
  - app.example.com    # additional names as needed

Fix 4: Ingress Not Annotated for cert-manager

WRONG β€” creating a Certificate manually without Ingress annotation:

# Ingress missing cert-manager annotation:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  # no annotation β€” cert-manager does not auto-create certs

RIGHT β€” add the annotation for auto-certificate:

metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - example.com
    secretName: example-tls

Fix 5: DNS-01 Challenge Fails

kubectl describe certificate example-tls
# Reason:  ACMEChallenge
# Message: Failed to complete ACME dns-01 challenge:
#   DNS problem: NXDOMAIN looking up TXT for _acme-challenge.example.com

RIGHT β€” verify DNS delegation for the _acme-challenge subdomain:

spec:
  solvers:
  - dns01:
      cloudflare:
        email: admin@example.com
        apiTokenSecretRef:
          name: cloudflare-token
          key: api-token

Fix 6: Secret Not Created

kubectl get secret example-tls
# Error: secret "example-tls" not found

RIGHT β€” describe the certificate and check the error:

kubectl describe certificate example-tls
# If the issuer is ready and DNS is configured, the secret is created after
# the certificate is issued. Check cert-manager logs:
kubectl logs -n cert-manager deployment/cert-manager

Use DodaTech's Certificate Dashboard to monitor cert-manager issuers, certificate expiry, and auto-remediate failed ACME challenges.

Prevention

  • Verify DNS records before creating certificates.
  • Use ClusterIssuer for cluster-wide certificate issuance.
  • Annotate Ingress resources for automatic certificate management.
  • Monitor certificate expiry and set renewal notifications.
  • Keep cert-manager updated to the latest version.

Common Mistakes with cert manager

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to exit a function early instead of wrapping a pure value in the monad

These mistakes appear frequently in real-world K8S code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why is my Issuer stuck on "ACMEAccountRegistrationFailed"?

The ACME server (Let's Encrypt) rate-limited your account registration. Wait 1 hour and retry. Check that the email address in the issuer spec is valid. Use the staging server https://acme-staging-v02.api.letsencrypt.org/directory for testing.

What is the difference between Issuer and ClusterIssuer?

Issuer is namespace-scoped β€” only certificates in the same namespace can use it. ClusterIssuer is cluster-scoped β€” certificates from any namespace can reference it. Use ClusterIssuer for shared Let's Encrypt configurations.

How does cert-manager renew certificates?

cert-manager tracks certificate expiry and automatically renews when the certificate is within 30 days of expiry. It sets the renewBefore option (default 30 days). Check kubectl get certificate for the renewal time.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro