K3s Traefik: Disable or Replace the Default Ingress

The K3s Traefik Ingress controller is failing to start because it’s trying to bind to a port that’s already in use by another process, which is usually the default Traefik instance that K3s installs for you.

Common Causes and Fixes

  1. Default Traefik is Running: K3s bundles Traefik by default. If you’re trying to deploy your own Traefik or another ingress controller, the bundled one is likely already occupying ports 80 and 443.

    • Diagnosis: Check if the traefik pods are running in the kube-system namespace:

      kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik
      

      If you see pods, it’s the default.

    • Fix: Disable the bundled Traefik by setting the --disable traefik flag when you start or upgrade K3s. For example, if you’re using k3sup, it would look like:

      k3sup install --cluster --disable traefik
      

      This prevents K3s from installing its default ingress controller, freeing up the ports.

    • Why it works: This flag tells K3s’s internal installer not to deploy the Traefik Helm chart, thus preventing the port conflict.

  2. Another Ingress Controller is Running: You might have installed a different ingress controller (like Nginx Ingress) before attempting to use Traefik, and it’s already claimed ports 80 and 443.

    • Diagnosis: List all ingress controllers and check which ones are active. A common way to check is to look at the ingressclass.kubernetes.io/is-default-class annotation on IngressClass resources.

      kubectl get ingressclass
      

      Look for any ingressclass that has IS-DEFAULT-CLASS: true and is not your intended Traefik. Also, check for pods in ingress-nginx or similar namespaces.

    • Fix: If you find another controller, you must either uninstall it or reconfigure it to use different ports (which is generally not recommended for standard HTTP/S ingress). To uninstall, follow the specific instructions for that controller. For Nginx ingress, it might be:

      kubectl delete -f <path-to-nginx-ingress-installation.yaml>
      # or if installed via Helm
      helm uninstall nginx-ingress -n ingress-nginx
      
    • Why it works: Removing the conflicting ingress controller frees up the necessary ports on the host nodes.

  3. Host Network Ports Already in Use: Even if you disable K3s’s default Traefik and don’t have another ingress controller, a process outside of Kubernetes might be listening on ports 80 or 443 on your K3s node(s). This is common on development machines or if you’ve manually started a web server.

    • Diagnosis: On each K3s node, run:

      sudo netstat -tulnp | grep -E ':80|:443'
      

      This will show you which process (if any) is listening on those ports.

    • Fix: Stop the offending process. For example, if apache2 or nginx is running:

      sudo systemctl stop apache2
      sudo systemctl disable apache2
      # or
      sudo systemctl stop nginx
      sudo systemctl disable nginx
      

      If it’s an unknown process, identify it using the PID from netstat and stop it.

    • Why it works: This ensures that when your Traefik pods try to bind to the host ports (via hostPort or NodePort), no other process is already using them.

  4. Incorrect Traefik Deployment Configuration: You might be trying to deploy your own Traefik, but the Helm chart or manifest is misconfigured, perhaps trying to expose ports that are already managed by the K3s system itself in a way that conflicts.

    • Diagnosis: Examine the deployment YAML or Helm values for your Traefik installation. Look for hostPort definitions or NodePort service types that might be attempting to claim ports 80 or 443.

      kubectl get service -n <your-traefik-namespace> -o yaml
      

      Specifically, check the ports section for nodePort values.

    • Fix: If using Helm, ensure you are not overriding the default ports if you intend to use Traefik’s default behavior for ingress, or carefully select different NodePort values if absolutely necessary and you know they are free. If deploying manually, remove any hostPort definitions that conflict. A common pattern is to let Traefik use LoadBalancer or NodePort where the system manages port allocation. For a typical setup where you want Traefik to handle ingress, you’d often use:

      # Example snippet for a Traefik service
      apiVersion: v1
      kind: Service
      metadata:
        name: traefik
        namespace: traefik # or kube-system if installed that way
      spec:
        type: NodePort # Or LoadBalancer if available
        ports:
          - name: web
            port: 80
            targetPort: 80
            protocol: TCP
            nodePort: 30080 # Example, ensure this is free or let K8s assign
          - name: websecure
            port: 443
            targetPort: 443
            protocol: TCP
            nodePort: 30443 # Example, ensure this is free or let K8s assign
      

      If you are disabling K3s’s default Traefik, you’d deploy your own Traefik with a NodePort service on ports 80/443 (or other ports if you’re proxying through an external load balancer).

    • Why it works: Correctly configuring the Traefik service to use NodePort (and ensuring those specific nodePort numbers are not already taken, or letting Kubernetes assign them) or LoadBalancer allows Traefik to receive traffic without direct host port conflicts.

  5. IP Address Binding Issues: In some very specific network configurations, Traefik might be configured to bind to a specific IP address on the node that is either not available or already in use by another interface or service. This is less common with standard K3s setups.

    • Diagnosis: Check the Traefik deployment configuration. Look for arguments like --entrypoints.web.address or --entrypoints.websecure.address in the Traefik container’s command or args.

      kubectl get pods -n <your-traefik-namespace> -o yaml
      

      Inspect the command and args for the Traefik container.

    • Fix: Remove any explicit IP address binding. Traefik should, by default, bind to 0.0.0.0 to listen on all available interfaces for the node. If you see something like --entrypoints.web.address=:80, change it to --entrypoints.web.address=0.0.0.0:80. If you are using a hostPort on the service, the hostPort definition itself implicitly binds to all interfaces for that port on the node.

    • Why it works: Binding to 0.0.0.0 ensures Traefik listens on all network interfaces on the node, making it discoverable via the node’s IP and the assigned NodePort or LoadBalancer IP, without conflicting with specific interface bindings.

The next error you’ll likely encounter after fixing this is Traefik reporting that it cannot find any Ingress resources to manage, or your applications not being accessible via the ingress.

Want structured learning?

Take the full K3s course →