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.

5 minutes reading time

Written by

Saiyam Pathak
Saiyam Pathak

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-manager
The 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.config
Merged 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 nodes
NAME STATUS ROLES AGE VERSION
k3s-https-civo-4ba6-29bb47-node-pool-7071-t6g2y Ready <none> 2m14s v1.22.11+k3s1
k3s-https-civo-4ba6-29bb47-node-pool-7071-fi3vh Ready <none> 94s v1.22.11+k3s1
k3s-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 traefik
pod/helm-install-traefik-crd-sjmk5 0/1 Completed 0 3m4s
pod/helm-install-traefik-2f6dq 0/1 Completed 2 3m4s
pod/traefik-znjw7 1/1 Running 0 2m15s
pod/traefik-svwxg 1/1 Running 0 2m15s
pod/traefik-6nqhm 1/1 Running 0 59s
service/traefik LoadBalancer 10.43.157.236 74.220.22.175 80:32429/TCP,443:32409/TCP 2m16s
daemonset.apps/traefik 3 3 3 3 3 <none> 2m17s
$ kubectl get pods -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-848f547974-z88kf 1/1 Running 0 3m39s
cert-manager-cainjector-54f4cc6b5-n26m5 1/1 Running 0 3m39s
cert-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/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: default
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: saiym911@gmail.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- 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/v1
kind: Certificate
metadata:
name: demo
namespace: default
spec:
secretName: demo
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
commonName: demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com
dnsNames:
- 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: Deployment
apiVersion: apps/v1
metadata:
name: nginx-demo
namespace: default
labels:
app: nginx-demo
spec:
replicas: 1
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: "nginx"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-demo
namespace: default
spec:
selector:
app: nginx-demo
ports:
- name: http
targetPort: 80
port: 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 pods
NAME READY STATUS RESTARTS AGE
nginx-demo-7d56b74b84-h6zww 1/1 Running 0 80s
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 16m
nginx-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/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: traefik
name: nginx-ingress
namespace: default
spec:
rules:
- host: demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com
http:
paths:
- backend:
service:
name: nginx-demo
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- demo.0d652485-6bb6-465f-b3b3-eb12485d9aee.lb.civo.com
secretName: demo

Once applied, you will be able to see that the ingress has been created by the following result:

$ kubectl get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-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 and
working. 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:

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.

Saiyam Pathak
Saiyam Pathak

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.

View author profile

Further Reading

Slide 1 of 2