cert-manager runs the full ACME DNS-01 challenge against Cloudflare to issue a wildcard cert for *.in.alybadawy.com. The resulting wildcard-tls Secret is loaded by ingress-nginx as its default certificate — every HTTPS hostname in the cluster gets the wildcard automatically, with zero per-Ingress configuration.
01 Three-component architecture
TLS works because three resources are set up correctly and in the right order:
- ClusterIssuer
letsencrypt-prod— tells cert-manager how to talk to Let's Encrypt and how to prove domain ownership (DNS-01 via Cloudflare API). - Certificate
wildcard-in-alybadawy-com— requests the actual cert. cert-manager creates a DNS TXT record in Cloudflare, Let's Encrypt verifies it, cert-manager stores the result in thewildcard-tlsSecret. - ingress-nginx
default-ssl-certificate— tells nginx to loadwildcard-tlsfor all incoming HTTPS connections. Per-Ingresstls[]blocks are not needed.
02 ClusterIssuer
Two issuers exist: letsencrypt-prod (used by default) and letsencrypt-staging (for testing without hitting rate limits). Both use DNS-01 with the Cloudflare solver. cert-manager is configured to query 8.8.8.8 and 1.1.1.1 directly for propagation checks, bypassing any local DNS that might not see the TXT record yet.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: alybadawy@icloud.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token # seeded by provision/bootstrap-argocd in step 7
03 The wildcard Certificate
One Certificate resource covers every current and future hostname under in.alybadawy.com. Adding a new service never requires touching cert-manager.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-in-alybadawy-com
namespace: networking
annotations:
argocd.argoproj.io/sync-wave: "2" # after ClusterIssuer at wave 1
spec:
secretName: wildcard-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
commonName: "*.in.alybadawy.com"
dnsNames:
- "*.in.alybadawy.com"
- "in.alybadawy.com"
cert-manager automatically renews the cert before expiry. Let's Encrypt certs are valid for 90 days; renewal starts at 60 days. When cert-manager writes an updated wildcard-tls Secret, ingress-nginx hot-reloads it — no downtime, no manual steps.
04 Adding a new service
Because TLS is handled globally, adding a new HTTPS service requires zero cert-manager configuration:
- Create an
Ingressresource withingressClassName: nginxand your hostname. - Add
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"for HTTP→HTTPS redirect. - Do not add
cert-manager.io/cluster-issuer. Do not add atls[]block.
The wildcard cert already covers the new hostname. nginx serves it automatically.
05 Troubleshooting
# certificate status and expiry
$ kubectl get certificate wildcard-in-alybadawy-com -n networking
NAME READY SECRET AGE
wildcard-in-alybadawy-com True wildcard-tls 5d
# verify SANs and expiry date
$ kubectl get secret wildcard-tls -n networking \
-o jsonpath='{.data.tls\.crt}' | base64 -d \
| openssl x509 -noout -text | grep -A2 "Subject Alternative\|Not After"
# watch cert-manager reconcile (useful during first issuance)
$ kubectl logs -n networking -l app.kubernetes.io/name=cert-manager --tail=50
_acme-challenge.in.alybadawy.com TXT record requires Cloudflare to have an explicit A or CNAME record for in.alybadawy.com — without it, Cloudflare's DNS will store the TXT but not serve it. Both in.alybadawy.com and *.in.alybadawy.com should have CNAME records pointing to alybadawy.com (unproxied).