Skip to main content

Set up a Let's Encrypt ClusterIssuer

Let's Encrypt's ClusterIssuer enables cert-manager to automatically request, validate, and renew publicly trusted TLS certificates across every namespace in your cluster. Using the Automated Certificate Management Environment (ACME) protocol, cert-manager verifies domain ownership with Let's Encrypt before issuing certificates into Kubernetes Secrets. Once configured, you simply annotate an Ingress or Certificate resource, and cert-manager manages the full certificate lifecycle. This guide assumes .

Start on Let's Encrypt's staging server

Let's Encrypt rate-limits⁠ how many certificates you can request for a domain on the production environment, and a misconfigured issuer can exhaust that limit quickly. Use the staging environment⁠ until the flow works end to end, then switch to production. Staging certificates are not trusted by browsers, which is precisely why they are safe to iterate against.

clusterissuer-staging.yamlyaml
		apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: you@example.com
    privateKeySecretRef:
      name: letsencrypt-staging-account
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx
	

Switch the server to https://acme-v02.api.letsencrypt.org/directory and rename the issuer to letsencrypt-prod once staging issues certificates cleanly.

Prove domain control: HTTP-01 or DNS-01

Before Let's Encrypt signs a certificate, ACME requires cert-manager to prove you control the domain. It runs one of two challenge types, and the one you choose determines whether you can issue wildcards.

HTTP-01⁠ proves control by serving a token over HTTP through your ingress. It works for any host that already points to your load balancer and requires no DNS credentials. cert-manager adds a temporary ingress path for the challenge and removes it afterward. This is the http01 solver in the staging issuer above.

yaml
		solvers:
  - http01:
      ingress:
        ingressClassName: nginx
	

HTTP-01 cannot issue wildcard certificates.

Issue a certificate

Point an Ingress at the issuer with an annotation, and name the Secret that cert-manager should populate:

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

Verify

cert-manager creates a Certificate object and, once the challenge passes, writes the Secret:

		$ kubectl get certificate
NAME                  READY   SECRET
app-example-com-tls   True    app-example-com-tls
$ kubectl describe certificate app-example-com-tls
	

READY: True means the certificate is issued and the ingress can serve HTTPS. If it remains False, the events on the Certificate and the Order/Challenge objects show which step failed, usually a DNS record that has not yet propagated or a challenge that could not reach the ingress.

Where to go next