Exposing your application to HTTPS with Kubernetes, Traefik and cert-manager
This tutorial will demonstrate how to expose our applications to the internet using HTTPS with the help of Civo Kubernetes, Traefik and cert-manager.
Written by
Head of Developer Relations @ vCluster
Written by
Head of Developer Relations @ vCluster
If you have created an application, you will need to expose it to the outside world through HTTPS. If you're working working with Kubernetes to deploy your application, you have powerful tools such as cert-manager and LetsEncrypt that can help you achieve this.
Throughout this tutorial, we will be setting everything up from scratch. This means the following guide can be applied to any Kubernetes cluster, but by using Civo Kubernetes it becomes easier as you have ready-to-use marketplace applications that will make things easier.
If you would like to try this on your own cluster that's not on Civo, you will need to install Traefik and cert-manager on your own. In this tutorial, I will add the installations commands separately for both Traefik and cert-manager.
Civo Kubernetes cluster creation
The first step of this process is to have a Kubernetes cluster created. For this tutorial, I will be using Civo Kubernetes as it is super fast with a <2 minute launch time. This will also allow me to utilize the power of Civo Marketplace which means I can install my favourite Kubernetes applications in seconds.
I will be using Civo CLI to create the cluster, which can be installed from here. If you would prefer to use the Civo web interface, you can do that too.
On the CLI, let's create our cluster:
civo k3s create https-civo --remove-applications=traefik2-nodeport --applications traefik2-loadbalancer,cert-managerThe cluster https-civo (45fab9fd-daaa-41ae-a1e8-7642d97f1c6b) has been created
The above example will create a 3 node cluster named https-civo, and install Traefik in loadbalancer mode, as well as cert-manager at the same time. Once the cluster is up and running in a couple of minutes, we can proceed.
We will then need to get the Kubeconfig for the cluster and save it to our desired location. If you do not specify a path, it will save it to the default location of ~/.kube/config:
civo k3s config https-civo --save --local-path /Users/saiyam/Downloads/https-civo.configMerged with main kubernetes config: /Users/saiyam/Downloads/https-civo.config
Let's make sure that kubectl knows to use our cluster's configuration file. Make sure you specify the path where you saved your configuration file:
$ export KUBECONFIG=/Users/saiyam/Downloads/https-civo.config$ kubectl get nodesNAME STATUS ROLES AGE VERSIONk3s-https-civo-4ba6-29bb47-node-pool-7071-t6g2y Ready <none> 2m14s v1.22.11+k3s1k3s-https-civo-4ba6-29bb47-node-pool-7071-fi3vh Ready <none> 94s v1.22.11+k3s1k3s-https-civo-4ba6-29bb47-node-pool-7071-5djri Ready <none> 13s v1.22.11+k3s1
We can also check if the Traefik Loadbalancer and cert-manager components are installed:
$ kubectl get all -n kube-system | grep traefikpod/helm-install-traefik-crd-sjmk5 0/1 Completed 0 3m4spod/helm-install-traefik-2f6dq 0/1 Completed 2 3m4spod/traefik-znjw7 1/1 Running 0 2m15spod/traefik-svwxg 1/1 Running 0 2m15spod/traefik-6nqhm 1/1 Running 0 59sservice/traefik LoadBalancer 10.43.157.236 74.220.22.175 80:32429/TCP,443:32409/TCP 2m16sdaemonset.apps/traefik 3 3 3 3 3 <none> 2m17s
$ kubectl get pods -n cert-managerNAME READY STATUS RESTARTS AGEcert-manager-848f547974-z88kf 1/1 Running 0 3m39scert-manager-cainjector-54f4cc6b5-n26m5 1/1 Running 0 3m39scert-manager-webhook-7c9588c76-xrrq9 1/1 Running 0 3m39s
If you are not using Civo Kubernetes, you need to install Traefik following the documentation and make sure you have some arguments passed such as the ones below:
- args:- --global.checknewversion- --global.sendanonymoususage- --entrypoints.metrics.address=:9100/tcp- --entrypoints.traefik.address=:9000/tcp- --entrypoints.web.address=:8000/tcp- --entrypoints.websecure.address=:8443/tcp- --api.dashboard=true- --ping=true- --metrics.prometheus=true- --metrics.prometheus.entrypoint=metrics- --providers.kubernetescrd- --providers.kubernetesingress- --providers.kubernetesingress.ingressendpoint.publishedservice=kube-system/traefik- --entrypoints.websecure.http.tls=true
To install cert-manager to a non-Civo Kubernetes cluster, you can run the below command:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
Now you should have a Kubernetes cluster with Traefik and cert-manager installed automatically if using Civo Kubernetes and selecting the apps during installation or manually using the mentioned methods above.
Create a Cluster Issuer
In order to get cert-manager to issue us a valid certificate, you need to create a Cluster Issuer resource in your cluster.
Change the email address in the snippet below, save it as clusterissuer.yaml and then apply the YAML file to the cluster with kubectl apply -f clusterissuer.yaml:
apiVersion: cert-manager.io/v1kind: ClusterIssuermetadata:name: letsencrypt-prodnamespace: defaultspec:acme:# The ACME server URLserver: https://acme-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: saiym911@gmail.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-prod# Enable the HTTP-01 challenge providersolvers:- http01:ingress:class: traefik
Once this has been applied you should see clusterissuer.cert-manager.io/letsencrypt-prod created returned from the cluster.
Create a certificate
For this step, you need to use your Traefik DNS or website configuration to create a certificate. When using Civo and the Civo CLI, you can find this out using the civo k3s show CLUSTER_NAME command and get the information from the Load balancers section shown in the output. It should look something like this:
Loadbalancers:+--------------------------------+-------------+---------------+--------------+-----------+--------------------------------------+--------------------------------------------------+| Name | Algorithm | Public IP | Private IP | State | Firewall | DNS Name |+--------------------------------+-------------+---------------+--------------+-----------+--------------------------------------+--------------------------------------------------+| https-civo-kube-system-traefik | round_robin | 74.220.22.175 | 192.168.1.52 | available | c9e14ae8-b8eb-4bae-a687-9da4637233da | 0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com |+--------------------------------+-------------+---------------+--------------+-----------+--------------------------------------+--------------------------------------------------+
Use the DNS name in the commonName and dnsNames sections of this, the Certificate resource definition:
apiVersion: cert-manager.io/v1kind: Certificatemetadata:name: demonamespace: defaultspec:secretName: demoissuerRef:name: letsencrypt-prodkind: ClusterIssuercommonName: demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.comdnsNames:- demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com
Save the file as certificate.yaml and apply it to your cluster with kubectl apply -f certificate.yaml.
Once this has been applied, you will get the result: certificate.cert-manager.io/demo created
Create the demo nginx app
Next, you will need to create the demo nginx application with a clusterIP service. This is the application that will be exposed on our cluster over HTTPS. Save the following as application.yaml:
kind: DeploymentapiVersion: apps/v1metadata:name: nginx-demonamespace: defaultlabels:app: nginx-demospec:replicas: 1selector:matchLabels:app: nginx-demotemplate:metadata:labels:app: nginx-demospec:containers:- name: nginximage: "nginx"---apiVersion: v1kind: Servicemetadata:name: nginx-demonamespace: defaultspec:selector:app: nginx-demoports:- name: httptargetPort: 80port: 80
You will need to apply this to your cluster, with kubectl apply -f application.yaml.
Once this is applied, you should be able to check for the application pod and service coming up with the relevant commands:
$ kubectl get podsNAME READY STATUS RESTARTS AGEnginx-demo-7d56b74b84-h6zww 1/1 Running 0 80s$ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.43.0.1 <none> 443/TCP 16mnginx-demo ClusterIP 10.43.130.181 <none> 80/TCP 84s
Create the ingress
Now is the time to create the ingress that will allow the application to be accessed from outside the cluster. Save the following definition YAML file, making sure you edit in the host to match your cluster's details:
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:annotations:cert-manager.io/cluster-issuer: letsencrypt-prodkubernetes.io/ingress.class: traefikname: nginx-ingressnamespace: defaultspec:rules:- host: demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.comhttp:paths:- backend:service:name: nginx-demoport:number: 80path: /pathType: Prefixtls:- hosts:- demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.comsecretName: demo
Once applied, you will be able to see that the ingress has been created by the following result:
$ kubectl get ingNAME CLASS HOSTS ADDRESS PORTS AGEnginx-ingress <none> demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com 74.220.22.175 80, 443 15s
Now, it's time to hit the HTTPS endpoint and feel the joy of exposing your application to the internet over HTTPS. You'll need to run the command curl -k https://demo.your-cluster-loadbalancer-id.lb.civo.com as follows:
$ curl -k https://demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>html { color-scheme: light dark; }body { width: 35em; margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif; }</style></head><body><h2>Welcome to nginx!</h2><p>If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.</p><p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p></body></html>
Or, you could hit the URL with your web browser:

You can see that the connection has been over HTTPS and the browser recognises the certificate as valid.
Conclusion
Now that we have reached the end of this tutorial, you have learned how to expose your applications to the internet with HTTPS using Civo Kubernetes, Traefik, and cert-manager (which can be installed via Civo Marketplace.

Head of Developer Relations @ vCluster
Saiyam Pathak is Head of Developer Relations at vCluster and a prominent advocate in the cloud-native and Kubernetes community. He is also the founder of Kubesimplify, a platform dedicated to simplifying Kubernetes and cloud-native technologies through educational content.
Saiyam has previously worked at organizations including Civo, Walmart Labs, Oracle, and HP, gaining experience across machine learning platforms, multi-cloud infrastructure, and managed Kubernetes services. He actively contributes to the community through technical content, meetups, and open-source initiatives.
Share this article
Further Reading
14 November 2022
Managing application secrets with Vault
2 January 2024