Configuring Ingress and TLS Certificates with Traefik and Cert-Manager
Introduction
This setup provides a robust solution for exposing services on your local network or the internet with valid SSL/TLS certificates. By combining Traefik's routing capabilities with Cert-Manager's certificate automation (using Cloudflare DNS challenge in this example), you avoid browser security warnings and ensure encrypted traffic. This method avoids using Traefik's built-in ACME storage, which can be problematic with persistent volumes in clustered environments, preferring Cert-Manager's Kubernetes-native secret management.
Prerequisites:
-
Running Kubernetes Cluster: A working cluster (e.g., K3s) with nodes ready.
-
Load Balancer:
kube-vipinstalled to provide a stable LoadBalancer IP for Traefik. -
Helm Installed: The Helm package manager must be installed on your workstation.
-
Domain Name: A domain managed by a provider that supports DNS challenges (we are using Cloudflare in this guide).
Install Traefik
We will use Helm to install Traefik. We'll force it to redirect to HTTPS and manually assign your Kube-Vip IP so it remains static via Helm values file.
Create the file traefik-values.yaml
# 1. High Availability
# Run 2 replicas so if one node goes down, Traefik stays up.
# deployment:
# replicas: 2
# 2. Service Configuration & Kube-VIP
service:
type: LoadBalancer
# This annotation tells kube-vip which specific IP to advertise
annotations:
kube-vip.io/loadbalancerIPs: "192.168.100.101"
# 3. Port Configuration & HTTPS Redirect
ports:
web:
# Forces all HTTP (port 80) traffic to redirect to HTTPS (port 443)
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
tls:
enabled: true
Add Traefik to the helm repo and install with the arguments from traefik-values.yaml
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik -n traefik --create-namespace --values traefik-values.yaml
Verify the installation. You should see a LoadBalancer service with the external IP you have set as the load balancer IP.
kubectl get pods -n traefik
kubectl get svc -n traefik
Deploy Cert-Manager
Cert-Manager is a native Kubernetes certificate management controller. Its primary purpose is to automate the issuance and renewal of SSL/TLS certificates from various sources, such as Let's Encrypt, HashiCorp Vault, or self-signed CAs. It ensures certificates are valid and up-to-date, storing them as standard Kubernetes Secrets so they can be easily consumed by Ingress Controllers (like Traefik) without complex volume mounts.
Add cert-manager repo
helm repo add jetstack https://charts.jetstack.io
helm repo update
Create cert-manager-values.yaml
crds:
enabled: true
namespace: "cert-manager"
extraArgs:
- --dns01-recursive-nameservers-only
- --dns01-recursive-nameservers=1.1.1.1:53,1.0.0.1:53
Install cert-manager
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --values cert-manager-values.yaml
Cloudflare DNS-01 Challenge Setup
We will use Cloudflare for the DNS-01 challenge, which allows issuing certificates for internal IPs/domains as long as you own the public domain.
Cloudflare API Token
You must give cert-manager permission to edit your DNS records.
-
Go to the Cloudflare Dashboard.
-
Create Token -> Use the Edit zone DNS template.
-
Permissions: *
Zone->DNS->Edit-
Zone->Zone->Read
-
-
Zone Resources:
Include->Specific zone->.penguincave.linkyourdomain.com -
Copy the Token (e.g.,
zXy...).
Install Traefik
We will use Helm to install Traefik. We'll manually assign your Kube-Vip IP so it remains static.
# Add the Traefik repo
helm repo add traefik https://traefik.github.io/charts
helm repo update
# Create a namespace for networking
kubectl create namespace traefik
# Delete if there's an existing config
# Install Traefik
# Replace 192.168.1.50 with your actual Kube-Vip IP
kubectl delete ingressclass traefik --ignore-not-found=true
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--set deployment.replicas=2 \
--set service.type=LoadBalancer \
--set "service.annotations.kube-vip\\.io/loadbalancerIPs=192.168.100.101" \
--set "ports.web.redirections.entryPoint.to=websecure" \
--set "ports.web.redirections.entryPoint.scheme=https" \
--set "ports.web.redirections.entryPoint.permanent=true"What this does:It sets up two Traefik pods for HA and tells Kube-Vip to bind them to your specific IP. It also forces all HTTP traffic to jump to HTTPS automatically.
Deploy Support Tools (Cert-Manager & Reflector)
We need the "Secretary" to manage the certs and the "Mirror" to share them.
# 1. Install Cert-Manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
# 2. Install Reflector via OCI registry (standard for new versions)
helm upgrade --install reflector oci://ghcr.io/emberstack/helm-charts/reflector \
--namespace kube-system
Phase 3: Cloudflare DNS-01 Setup
This part connects your Cloudflare API to the cluster and requests the certificate.
1. Create the API Token Secret
kubectl create secret generic cloudflare-api-token-secret \
-n cert-manager \
--from-literal=api-token=YOUR_ACTUAL_CLOUDFLARE_TOKEN
2. Create the ClusterIssuer (): issuer.cert-manager-clusterissuer.yamlNote: Use a real email address to avoid ACME registration errors.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cloudflare
spec:
acme:
email: your-real-email@gmail.email@email.com
# do not forget to put your email address
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-cloudflare-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
PhaseApply:
4:
Thekubectl Wildcardapply Certificate
-f kubectl Wildcardapply CertificateThis creates the master certificate in the traefik namespace. Reflector then mirrors it cluster-wide.
Create wildcard-cert.cert-manager-clusterissuer.yaml:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: homelab-wildcard
namespace: traefik
spec:
secretName: homelab-wildcard-tls
issuerRef:
name: letsencrypt-cloudflare
kind: ClusterIssuer
dnsNames:
- "*.homelab.penguincave.link"
secretTemplate:
annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"Phase 5: High Availability Test (NGINX)
ThisHere's ensuresan 3example replicasNGINX aredeployment, spreadservice acrossand youringress 3in masterone nodesfile usingto Podtest Anti-Affinity.with:
Create nginx-ha.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ha
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ["nginx"]
topologyKey: "kubernetes.io/hostname"
containers:
- name: nginx
image: nginx:latest
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- port: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
ingressClassName: traefik
tls:
- hosts: ["nginx.homelab.penguincave.link"]
secretName: homelab-wildcard-tls
rules:
- host: nginx.homelab.penguincave.link
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
Troubleshooting
Apply:
kubectl apply -f nginx-ha.yaml
Now that we have a test deployment, we'll need to setup the certificate for it.
Create nginx-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: nginx-cert # cert name!
namespace: nginx # Namespace where your app is running
spec:
secretName: nginx-cert-secret # The name of the secret where the cert will be stored
issuerRef:
name: letsencrypt-cloudflare
kind: ClusterIssuer
dnsNames:
- "nginx.homelab.penguincave.link"
You may need to wait for a moment that might take for a few hours for the DNS to propagate and to validate the DNS challenge. You may check it by using this command to watch for your certificate:
kubectl get certificate -n nginx -w
If it's taking a while, look for errors in the logs:
-
Check Cert Status:
kubectl get cert -n traefik -
Check DNS Challenge:
kubectl describe challenge -n traefik Check Secret Mirroring:kubectl get secret homelab-wildcard-tls -n longhorn-systemCheck Pod Distribution:kubectl get pods -o wide
WouldOnce "True" you likeshould mebe able to createbrowse ayour singlenginx bashdeployment scriptwith thatworking automatesand thesesecure installationsTLS forcertificates. future:)


