The Challenge
When I first set up Traefik as my ingress controller in my K3s cluster, everything worked fine for internal services running within Kubernetes. However, I ran into issues when trying to expose external services β like my Proxmox server β through Traefik while ensuring proper routing, TLS, and domain handling.
The Goal
My goal was to access My Proxmox web gui via Traefik using the domain juliette.home.m23homelab.org, while ensuring:
- Proper TLS handling with Let’s Encrypt (via cert-manager).
- Secure HTTPS passthrough without Traefik interfering.
- Correct routing through an ExternalName service in Kubernetes.
I got help from @dasop on Discord, who pointed me in the right direction!
The Working Solution
After a lot of troubleshooting, I managed to get it working with the following Kubernetes manifests:
1. The ExternalName Service
This service maps the internal Proxmox instance to a Kubernetes service so that Traefik can route traffic to it.
apiVersion: v1 kind: Service metadata: name: proxmox-juliette namespace: default annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure # 2 Lines Below required if app/endpoint uses https! if http dont uncomment. traefik.ingress.kubernetes.io/service.serverstransport: default-insecure-transport@kubernetescrd traefik.ingress.kubernetes.io/service.serversscheme: https spec: type: ExternalName externalName: 192.168.178.170 # Proxmox server internal IP ports: - port: 8006 targetPort: 8006 protocol: TCP
Explanation:
- ExternalName Service: This service acts as a proxy to an external IP (192.168.178.170).
- Traefik Annotations:
- service.serverstransport: default-insecure-transport@kubernetescrd: This tells Traefik to use the insecure transport, allowing it to communicate with self-signed HTTPS services.
- service.serversscheme: https: This ensures that Traefik properly routes traffic using HTTPS instead of defaulting to HTTP.
2. The Ingress
This Ingress definition tells Traefik how to route external requests to the Proxmox service.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: proxmox-juliette-ingress namespace: default annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" external-dns.alpha.kubernetes.io/hostname: juliette.home.m23homelab.org cert-manager.io/cluster-issuer: cloudflare-clusterissuer spec: tls: - hosts: - juliette.home.m23homelab.org secretName: proxmox-juliette-certificate-secret rules: - host: juliette.home.m23homelab.org http: paths: - path: / pathType: Prefix backend: service: name: proxmox-juliette port: number: 8006
- TLS Setup: This uses cert-manager to issue a TLS certificate via Cloudflare DNS.
- Ingress Rules: Any request to juliette.home.m23homelab.org is forwarded to the Proxmox service.
3. ServerTransport Manifest (For Insecure HTTPS Backends)
Since Proxmox uses a self-signed certificate, we need to allow Traefik to skip certificate verification for this backend.
apiVersion: traefik.io/v1alpha1 kind: ServersTransport metadata: name: default-insecure-transport namespace: default spec: insecureSkipVerify: true
Explanation:
- insecureSkipVerify: true allows Traefik to communicate with self-signed HTTPS services without failing due to certificate validation errors.
- This is referenced in the Service manifest via traefik.ingress.kubernetes.io/service.serverstransport: default-insecure-transport@kubernetescrd.
Lessons Learned
- External services require an ExternalName service in Kubernetes, rather than directly exposing them via Ingress.
- If an external service uses HTTPS, Traefik must be told to use serversscheme: https, or it defaults to HTTP.
- For self-signed certificates, a ServersTransport resource is required to allow insecure connections.
- DNS management is handled by external-dns and cert-manager, making domain and TLS automation seamless.
Final Thoughts
With this setup, I can now securely access my Proxmox Web UI through Traefik using my domain, with full TLS support. This method also applies to other external services, like router UIs, other servers, or web applications outside the cluster. Huge thanks to @dasop on Discord for pointing me in the right direction!