How to Install Traefik Ingress controller with Cert-Manager on Kubernetes

Updated on 13 May, 2025
Learn to secure a VKE cluster using Traefik, cert-manager, and Let's Encrypt for enhanced application security and automatic HTTPS redirection.
How to Install Traefik Ingress controller with Cert-Manager on Kubernetes header image

The Traefik Kubernetes Ingress provider is an open-source Kubernetes Ingress controller. It integrates with cert-manager to provide a TLS certificate to expose the internal Services of your Kubernetes cluster securely.

In this article, you will install the Traefik Ingress controller on your Kubernetes cluster along with cert-manager to expose your applications securely using a TLS certificate. You will also create a sample application, create an internal Service for it, create an Ingress resource to expose that Service, and issue a TLS certificate using cert-manager.

Prerequisites

Before you begin, make sure you:

  • Have access to a Kubernetes cluster.
  • Install Kubect on your local machine.
  • Install the Helm client on your local machine.
  • Have access to a domain name. This guide uses example.com. Replace all occurrences with your actual domain.

Install and Configure Traefik

  1. Create a namespace traefik-namespace for the Traefik Ingress controller resources.

    console
    $ kubectl create namespace traefik-namespace
    
  2. Add the Traefik Helm repository.

    console
    $ helm repo add traefik https://helm.traefik.io/traefik
    
  3. Update your Helm chart repositories.

    console
    $ helm repo update
    
  4. Using Helm, install the Traefik Ingress controller.

    console
    $ helm install --namespace=traefik-namespace traefik traefik/traefik
    

    The above command installs the Traefik Ingress controller in the traefik-namespace you created earlier.

  5. Check the Traefik Ingress controller Service's external IP Address.

    console
    $ kubectl get services -n traefik-namespace
    

    Your output should look like the one below:

    NAME      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    traefik   LoadBalancer   10.108.209.185   <pending>     80:30046/TCP,443:30279/TCP   78s

    The EXTERNAL-IP value of the traefik Service is not allocated yet. Depending on your cloud provider, it may take some time for the traefik Service to get its external IP address. After some time, the output changes to:

    NAME      TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
    traefik   LoadBalancer   10.107.61.70   192.0.2.10      80:30351/TCP,443:32047/TCP   9m34s
  6. Visit your Domain DNS registrar. For example, Vultr DNS.

  7. Set up a domain A record pointing to the Traefik LoadBalancer external IP Address.

Install cert-manager

cert-manager is a Kubernetes custom resource that can issue TLS certificates from different Certificate Authorities, such as Let's Encrypt, HashiCorp Vault, Venafi, and many more. It also ensures that the certificates are valid and up to date by actively attempting to renew them before they expire. In this section, you will install cert-manager on your Kubernetes cluster.

  1. Install the latest cert-manager version on your cluster.

    console
    $ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
    

    The above command installs version v1.17.2 of cert-manager. To find the latest cert-manager version, visit the cert-manager GitHub repository.

  2. Verify that all cert-manager components are installed and running.

    console
    $ kubectl get pods --namespace cert-manager
    

    You should see resources with cert-manager in their names in the output.

Create a ClusterIssuer

ClusterIssuer is a cluster-scoped custom resource that comes with cert-manager. It issues TLS certificates for Ingress resources. In this section, you will create a ClusterIssuer resource to issue Let's Encrypt certificates.

  1. Create a new file named cluster-issuer.yaml.

    console
    $ nano cluster-issuer.yaml
    
  2. Add the following contents to the file.

    yaml
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        email: hello@example.com
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-prod-key
        solvers:
          - http01:
              ingress:
                class: traefik
    
    Note
    Do not specify an email of example.com domain, specify a valid email address. Otherwise, the ClusterIssuer resource would not work.

    Below is what the above configuration declarations represent:

    • acme: Specifies the ACME configuration for the CA, which is Let's Encrypt in this case.
    • email: Your email address to associate with a Let's Encrypt account.
    • server: The ACME server URL.
    • privateKeySecretRef: Specifies the Secret that holds the Let's Encrypt account private key.
    • solvers: Sets the method for solving the ACME challenge.
    • http01: Sets HTTP-01 as the challenge solver to verify domain ownership.
    • ingress: Sets the ingress class to solve the challenge.

    Save and close the file.

  3. Apply the manifest file.

    console
    $ kubectl apply -f cluster-issuer.yaml
    
  4. Check the ClusterIssuer.

    console
    $ kubectl get clusterissuer
    

    Output:

    NAME               READY   AGE
    letsencrypt-prod   True    2m44s

    Notice the True value of the READY field. It indicates that the ClusterIssuer resource is ready to issue certificates.

Deploy a Sample Application

In this section, you will deploy a sample application based on the Nginx web server to test your Traefik configuration and the cert-manager certificate issuance process.

  1. Create a new namespace, example-app-namespace, to store the resources of the sample application.

    console
    $ kubectl create namespace example-app-namespace
    
  2. Create a new Deployment file named example-app-deployment.yaml.

    console
    $ nano example-app-deployment.yaml
    
  3. Add the following contents to the file.

    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: example-app-namespace
      name: example-app-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: example-app
      template:
        metadata:
          labels:
            app: example-app
        spec:
          containers:
            - name: web-app
              image: nginx
              ports:
                - containerPort: 80
    

    This manifest file creates a Deployment example-app-deployment that uses the Nginx web-server image and creates three replicas.

    Below is what the Deployment configurations represent:

    • replicas: The number of replicas (pods) of the Deployment.
    • selector: The labels used for selecting the pods controlled by the Deployment.
    • template: Specifies the template for creating the pods.
    • metadata: Specifies the labels for the pods.
    • spec: Specification for the pods.
    • containers: Specifies the containers within the pods.
    • name: Specifies the container name.
    • image: Container image of the pods.
    • ports: Ports opened in the container.

    Save and close the file.

  4. Apply the Deployment manifest.

    console
    $ kubectl apply -f example-app-deployment.yaml
    

    The above command creates the Deployment example-app-deployment in the namespace example-app-namespace.

  5. Verify that the example application pods are running.

    console
    $ kubectl get pods -n example-app-namespace
    

    You should see three pods with names starting with example-app-deployment- listed in the output.

Create an Ingress Resource

In this section, you will create a Service for your Deployment and then create an Ingress resource to expose that Service externally using a TLS certificate.

  1. Create a new Service manifest file named example-app-service.yaml.

    console
    $ nano example-app-service.yaml
    
  2. Add the following contents to the file.

    yaml
    apiVersion: v1
    kind: Service
    metadata:
      namespace: example-app-namespace
      name: example-app-service
    spec:
      selector:
        app: example-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 80
    

    This creates a Service example-app-service that exposes the pods of your Deployment example-app-deployment.

    Below is what the Service manifest represent:

    • spec: Describes the Service's specification.
    • selector: Specifies a set of labels used to select the pods to which the Service should route traffic.
    • app: Specifies a label named app with the value example-app.
    • ports: Defines the ports exposed by the Service.
    • protocol: Specifies the protocol to use for the ports.
    • port: The port number the Service should listen on.
    • targetPort: Specifies the port number to which traffic should be forwarded within the pods.

    Save and close the file.

  3. Apply the Service manifest file.

    console
    $ kubectl apply -f example-app-service.yaml
    
  4. Verify that the Service is created.

    console
    $ kubectl get services -n example-app-namespace
    

    Output:

    NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    example-app-service   ClusterIP   10.97.221.68   <none>        80/TCP    81s
  5. Create a new Ingress manifest file example-app-ingress.yaml.

    console
    $ nano example-app-ingress.yaml
    
  6. Add the following contents to the file. Replace example.com with your actual domain.

    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: web-app-ingress
      namespace: example-app-namespace
      annotations:
        traefik.ingress.kubernetes.io/router.entrypoints: websecure
        traefik.ingress.kubernetes.io/router.tls: "true"
        cert-manager.io/cluster-issuer: letsencrypt-prod
    spec:
      rules:
        - host: example.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: example-app-service
                    port:
                      number: 80
      tls:
        - secretName: web-app-cert
          hosts:
            - example.com
    

    This manifest file creates an Ingress resource to expose your Service example-app-service for the domain name example.com.

    Below is what the Ingress declarations represent.

    • annotations: Specifies the annotations for the Ingress, including Traefik-specific and cert-manager-specific annotations.
    • traefik.ingress.kubernetes.io/router.entrypoints: websecure: Configures the Traefik ingress controller to route incoming traffic to the websecure entrypoint. It specifies the entrypoint to use for handling HTTPS traffic.
    • traefik.ingress.kubernetes.io/router.tls: "true": Specifies that the router should handle HTTPS traffic. It enables TLS termination and ensures secure communication between clients and the application.
    • cert-manager.io/cluster-issuer: letsencrypt-prod: Specifies the cert-manager cluster issuer to use for obtaining SSL/TLS certificates. It associates the Ingress resource with the letsencrypt-prod cluster issuer you created earlier.
    • spec: Specifies the specification for the Ingress.
    • rules: Specifies the rules for routing the traffic.
    • host: Specifies a domain/host to match the rule.
    • http: Specifies the HTTP routing for the host.
    • paths: Specifies the paths to match within the host.
    • path: Specifies the path to match.
    • backend: Specifies the backend Service to route the traffic to.
    • service: Specifies the name of the to which to forward the traffic.
    • port: Specifies the port number of the Service to use.
    • tls: Specifies the TLS configuration for the Ingress resource.
    • secretName: Specifies the name of the Secret resource that stores the TLS certificate and private key. cert-manager creates this Secret resource. It need not be present before creating the Ingress.
    • hosts: Specifies the hostnames associated with the TLS certificate.

    Save and close the file.

  7. Apply the ingress configuration.

    console
    $ kubectl apply -f example-app-ingress.yaml
    
  8. Verify that the Ingress resource is created.

    console
    $ kubectl get ingress -n example-app-namespace
    

    Output:

    NAME                        CLASS     HOSTS                ADDRESS   PORTS     AGE
    web-app-ingress             traefik   example.com                    80, 443    9s

    The ADDRESS filed is empty right now. A few seconds later, its value populates. The value should be the external IP address of the traefik Service.

  9. Verify that a Let's Encrypt SSL certificate is registered for your domain.

    console
    $ kubectl get certificates -n example-app-namespace
    

    Output:

    NAME           READY   SECRET         AGE
    web-app-cert   True    web-app-cert   41s

    If the READY column returns True, your SSL certificate is successfully issued and ready to use. It may take some time for the Certificate resource to become ready.

  10. Verify that the certificate auto-renews on expiry.

    console
    $ kubectl describe -n example-app-namespace certificate web-app-cert
    

    The about command prints information about the certificate. Find the Renewal Time setting, and make sure its value is a date as below:

    ...
    Renewal Time:            2023-09-17T15:23:45Z
    ...
  11. In a web browser like Chrome, visit your domain name to access your application securely.

    https://example.com

    The default Nginx welcome page displays in your browser.

Troubleshooting

To manage Traefik and your cluster resources, below are troubleshooting tips for fixing common problems.

  • Unable to get Let's Encrypt Certificate: If your certificate column returns False, verify that your domain is correctly pointed to your Traefik LoadBalancer external IP Address. Additionally, to investigate further causes, view the cert-manager logs using the command below.

    console
    $ kubectl logs deployment/cert-manager  -n cert-manager --tail=15 -f
    
  • Check Traefik logs: If you're experiencing issues with Traefik, check the logs for any error messages or warnings using the following command.

    console
    $ kubectl logs -n <namespace> <traefik-pod>
    
  • Verify DNS configuration: Verify that your domain name is correctly pointed to the External IP address of your Traefik load balancer. Wrong DNS configurations prevent Traefik from handling incoming requests correctly.

  • Verify ingress configuration: If Traefik does not route external traffic correctly, check your Ingress resource configuration and verify that the necessary annotations for Traefik and cert-manager are included in your YAML file.

    console
    $ kubectl get ingress
    
  • Inspect Traefik resources: Occasionally, inspect the status of Traefik resources such as pods, Services, and ingresses to ensure they are running correctly.

    console
    $ kubectl get pods -n traefik-namespace
    

Conclusion

In this article, you installed the Traefik Ingress Controller. You created a web application and securely exposed it using Traefik, cert-manager, and Let's Encrypt. For more information and configuration options, visit the following resources:

Comments

No comments yet.