Securing NGINX-ingress via cert-manager

I think today (2025-07-11) marks the day I finally cracked cert-manager and LetsEncrypt. I have been struggling with HTTPS warnings and hosting self-signed certs. Let me tell you, it has been a right pain in the ass.
With the confusion of using a Cloudflare tunnel to point to my ingress controller's internal IP, and setting all that up. I was scratching my head for a while until I saw this clip on YouTube. Where Travis Media starts talking about TXT
records and DNS-01 challenges.
This challenge asks you to prove that you control the DNS for your domain name by putting a specific value in a TXT record under that domain name. It is harder to configure than HTTP-01, but it can work in scenarios that HTTP-01 can’t. It also allows you to issue wildcard certificates. After Let’s Encrypt gives your ACME client a token, your client will create a TXT record derived from that token and your account key, and put that record at _acme-challenge.<YOUR_DOMAIN>. Then Let’s Encrypt will query the DNS system for that record. If it finds a match, you can proceed to issue a certificate!
Lets get started...
Since my domain name 70ld.dev
is hosted on Cloudflare let's set that up.
To use Cloudflare, you will need an API Token These are application-scoped keys bound to specific zones and permissions. To create your API Token they can be created at User Profile > API Tokens > API Tokens. The following settings are recommended:
Permissions
- Zone - DNS - Edit
- Zone - Zone - Read
Zone Resources
- Include - All Zones
Now we have our key, encode it using base64
and create a secret.
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token-secret
type: Opaque
data:
api-token: <API Token>
Configure a Let's Encrypt ClusterIssuer
Now let's create a ClusterIssuer
if you follow the instructions on cert-manager's site it goes through setting up Issuer
but I want something cluster-wide as it's just my homelab. With the ClusterIssuer
you can see we're using solvers.dns01
which will allow us to use the DNS01 Challenge.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cloudflare-dns-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <email>
privateKeySecretRef:
name: letsencrypt-cloudflare-dns-issuer-secret
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
Now we can deploy everything and move on to creating an ingress with TLS.
Deploy an ingress with TLS
With everything in place, it's time to test it out by deploying an ingress with tls. So we can get cert-manager to use the DNS resolver and create a cert for us. Here is an example I have used for PGAdmin.
You will need to add the annotation of:
annotations:
cert-manager.io/cluster-issuer: '<ClusterIssuer Name>'
To tell the ingress to use the cluster issuer we created above. Then simply give the ingress some tls data
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: pgadmin-ingress
namespace: pgadmin
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: 'letsencrypt-cloudflare-dns-issuer'
spec:
ingressClassName: nginx
rules:
- host: pgadmin-prod.70ld.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: pgadmin-service
port:
number: 5050
tls:
- hosts:
- pgadmin-prod.70ld.dev
secretName: pgadmin-tls
Once you have deployed everything, cert manager should do its job and provide a cert for that application. I have noticed it can take some time, but for me it works nicely. I now don't have to worry about exposing my services outside of my network and I get TLS certs.