Service Routing with Traefik - External Services and URLs (Day 9)

Using Traefik to route traffic to services outside Kubernetes, e.g. Proxmox and OPNsense UIs, including SSL certificates.

Service Routing with Traefik - External Services and URLs (Day 9)

Having moved to a k3s deployed traefik, this covers setting up routes for services running outside the cluster.

Initial Traefik Configuration

First, we need to enable external name services in Traefik (add this to your traefik ingress deployment):

set:
  - name: providers.kubernetesCRD.allowExternalNameServices
    value: true

Route Organization

I'm keeping all routes separate from other deployments using a dedicated routes.yaml for helmfile:

releases:
  - name: routes
    namespace: routes
    chart: ./charts/routes

Certificate Setup

Assuming you have a ClusterIssuer already configured next we request a wildcard certificate for the services defined in the namespace.

I typically request wildcard certificates per namespace if there are multiple services needing ingress routes
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: routes-ns-ssl-cert
  namespace: routes
spec:
  commonName: "*.<your domain>"
  dnsNames:
    - "*.<your domain>"
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-dns01-issuer
  secretName: ssl-cert-prod

Traffic Management

HTTP to HTTPS Redirect

First, an HTTPS redirect middleware - this forces all incoming traffic to use HTTPS

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: https-redirect
  namespace: routes
spec:
  redirectScheme:
    scheme: https
    permanent: true

Handling Self-Signed Certs

For services like Proxmox and OPNsense that use self-signed certificates, we need to tell Traefik to skip verification:

apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
  name: insecure-skip-verify
  namespace: routes
spec:
  insecureSkipVerify: true

Setting Up Routes

1. Define the Service

First, create a service for your endpoint:

apiVersion: v1
kind: Service
metadata:
  name: opnsense
  namespace: routes
spec:
  ports:
    - port: 443
      targetPort: 443
  type: ExternalName
  externalName: 192.168.2.1 <this is the IP of the service you want to route to or its domain name>

2. Create Ingress Routes

You'll need two routes - one for HTTPS and one for HTTP redirect:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: opnsense
  namespace: routes
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`<the URL you want to the service to be reached on>`)
      kind: Rule
      services:
        - name: opnsense
          port: 443
          scheme: https
          serversTransport: insecure-skip-verify
  tls:
    secretName: ssl-cert-prod
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: opnsense-redirect
  namespace: routes
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`<the URL you want to the service to be reached on>`)
      kind: Rule
      middlewares:
        - name: https-redirect
      services:
        - name: noop@internal
          kind: TraefikService

3. Configure DNS Entries

Add your routes to your DNS provider:

<your defined url> -> traefik loadbalancer ip

Or if your DNS provider supports wildcards:

*.<your defined url> -> traefik loadbalancer ip

I'm using AdGuard Home, so it's just a matter of going to Filters > DNS rewrites and adding either a wildcard or specific URL.

4. Deploy the Routes

Review the changes first:

helmfile diff --file routes.yaml

Then deploy:

helmfile apply --file routes.yaml

You should now be able to access the service via the URL name used.