# cert-manager — noble **Prerequisites:** **Traefik** (ingress class **`traefik`**), DNS for **`*.apps.noble.lab.pcenicni.dev`** → Traefik LB for app traffic. **ACME (Let’s Encrypt)** uses **DNS-01** via **Cloudflare** for zone **`pcenicni.dev`**. Create an API token with **Zone → DNS → Edit** and **Zone → Zone → Read** (or use the “Edit zone DNS” template), then: ```bash kubectl -n cert-manager create secret generic cloudflare-dns-api-token \ --from-literal=api-token='YOUR_CLOUDFLARE_API_TOKEN' \ --dry-run=client -o yaml | kubectl apply -f - ``` Without this Secret, **`ClusterIssuer`** will not complete certificate orders. 1. Create the namespace: ```bash kubectl apply -f clusters/noble/apps/cert-manager/namespace.yaml ``` 2. Install the chart (CRDs included via `values.yaml`): ```bash helm repo add jetstack https://charts.jetstack.io helm repo update helm upgrade --install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --version v1.20.0 \ -f clusters/noble/apps/cert-manager/values.yaml \ --wait ``` 3. Optionally edit **`spec.acme.email`** in both ClusterIssuer manifests (default **`certificates@noble.lab.pcenicni.dev`**) — Let’s Encrypt uses this for expiry and account notices. Do **not** use **`example.com`** (ACME rejects it). 4. Apply ClusterIssuers (staging then prod, or both): ```bash kubectl apply -k clusters/noble/apps/cert-manager ``` 5. Confirm: ```bash kubectl get clusterissuer ``` Use **`cert-manager.io/cluster-issuer: letsencrypt-staging`** on Ingresses while testing; switch to **`letsencrypt-prod`** when ready. **HTTP-01** is not configured: if the hostname is **proxied** (orange cloud) in Cloudflare, Let’s Encrypt may hit Cloudflare’s edge and get **404** for `/.well-known/acme-challenge/`. DNS-01 avoids that.