How to Deploy a Secure Nginx Website on Vultr Kubernetes Engine

Updated on January 4, 2023
How to Deploy a Secure Nginx Website on Vultr Kubernetes Engine header image

Deploying an Nginx website on Vultr Kubernetes Engine will help you to achieve reliability and scalability. Protecting sensitive data and securing website traffic with SSL/TLS is also necessary for all websites. However, it can be challenging to host SSL/TLS-based Nginx websites on Kubernetes.

This is the case where Traefik Proxy comes into the picture. You can use and set up Traefik Proxy as a network proxy with a cert-manager to install and manage Let's Encrypt SSL certificates. Let's Encrypt is a free certificate authority that provides a way to automate and manage SSL certificates for your website.

This guide shows you how to secure the Nginx website with cert-manager, Traefik, and Let's Encrypt SSL on Vultr Kubernetes Engine.

Prerequisites

Install the Traefik Ingress Controller with Helm

  1. Add the Helm repository for the Traefik ingress controller.

     # helm repo add traefik https://helm.traefik.io/traefik
  2. Update the Helm repository.

     # helm repo update
  3. Install Traefik on your Kubernetes cluster.

     # helm install traefik traefik/traefik

    Sample output.

     NAME: traefik
     LAST DEPLOYED: Sat Nov 26 19:56:05 2022
     NAMESPACE: default
     STATUS: deployed
     REVISION: 1
     TEST SUITE: None
     NOTES:
     Traefik Proxy v2.9.5 has been deployed successfully on default namespace !
  4. Verify the Traefik ingress controller service.

     # kubectl get svc

    Sample output.

     NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
     kubernetes   ClusterIP      10.96.0.1      <none>        443/TCP                      5m16s
     traefik      LoadBalancer   10.96.215.40   192.0.2.100   80:31391/TCP,443:30688/TCP   3m

Creating Nginx Deployment and Service

Now, deploy an Nginx web server using the Nginx docker image on the Kubernetes cluster.

  1. Create an nginx-deployment.yml configuration file.

     # nano nginx-deployment.yml

    Add the following configuration:

     kind: Deployment
     apiVersion: apps/v1
     metadata:
       name: nginx-web
       namespace: default
       labels:
         app: nginx-web
     spec:
       replicas: 1
       selector:
         matchLabels:
           app: nginx-web
       template:
         metadata:
           labels:
             app: nginx-web
         spec:
           containers:
           - name: nginx
             image: "nginx"
  2. Apply the above configuration to the Kubernetes cluster.

     # kubectl create -f nginx-deployment.yml

    Sample output.

     deployment.apps/nginx-web created
  3. Create an Nginx service to expose pods to the cluster on port 80.

     # nano nginx-service.yml

    Add the following configuration.

     apiVersion: v1
     kind: Service
     metadata:
       name: nginx-web
       namespace: default
     spec:
       selector:
         app: nginx-web
       ports:
       - name: http
         targetPort: 80
         port: 80
  4. Apply the configuration to the Kubernetes cluster.

     # kubectl create -f nginx-service.yml

    Sample output.

     service/nginx-web created

Creating Traefik Ingress and Exposing Nginx Website

  1. Create a Traefik Ingress deployment to expose an Nginx website to the outside world.

     # nano traefik-ingress.yml

    Add the following configurations:

     apiVersion: networking.k8s.io/v1
     kind: Ingress
     metadata:
       name: traefik-ingress
       namespace: default
       annotations:
         kubernetes.io/ingress.class: traefik
     spec:
       rules:
       - host: nginxweb.example.com
         http:
           paths:
           - backend:
               service:
                 name: nginx-web
                 port:
                   number: 80
             path: /
             pathType: Prefix

    Note: Replace nginxweb.example.com with a fully qualified domain name.

  2. Apply the Traefik ingress resource to the cluster.

     # kubectl create -f traefik-ingress.yml   

    Sample output.

     ingress.networking.k8s.io/traefik-ingress created
  3. Verify the running pods.

     # kubectl get pods

    Sample output.

     NAME                         READY   STATUS    RESTARTS   AGE
     nginx-web-6b756d6954-mg5v4   1/1     Running   0          60s
     traefik-6c95797465-7ck46     1/1     Running   0          6m9s
  4. Verify the Kubernetes ingress resources.

     # kubectl get ingress

    Sample output.

     NAME              CLASS    HOSTS                   ADDRESS   PORTS   AGE
     traefik-ingress   <none>   nginxweb.example.com             80      119s
  5. Verify the Kubernetes service to retrieve the Traefik external IP.

     # kubectl get svc

    Sample output.

     NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
     kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP                      9m50s
     nginx-web    ClusterIP      10.104.168.40   <none>        80/TCP                       2m16s
     traefik      LoadBalancer   10.96.215.40    192.0.2.100   80:31391/TCP,443:30688/TCP   7m34s
  6. Point Traefik LoadBalancer external IP 192.0.2.100 to your domain name nginxweb.example.com.

Configuring cert-manager for Traefik Ingress

cert-manager is a certificate management controller for Kubernetes that allows you to download, renew and use Let's Encrypt or other SSL certificates.

Run the kubectl command to install cert-manager using the cert-manager's release file on the Kubernetes cluster.

# kubectl apply --validate=false -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml

Sample output.

service/cert-manager created
service/cert-manager-webhook created
deployment.apps/cert-manager-cainjector created
deployment.apps/cert-manager created
deployment.apps/cert-manager-webhook created
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created

Configuring and Creating Traefik Ingress Let's Encrypt TLS Certificate

  1. First, create the ClusterIssuer for the Kubernetes cluster to issue certificates from Let's Encrypt.

     # nano  letsencrypt-issuer.yml

    Add the following configurations.

     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: hitjethva@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
  2. Deploy the above configuration to the Kubernetes cluster.

     # kubectl apply -f letsencrypt-issuer.yml

    Sample output.

     clusterissuer.cert-manager.io/letsencrypt-prod created
  3. Create the Traefik Ingress Let's Encrypt TLS certificate for your Nginx website.

     # nano letsencrypt-certificate.yml

    Add the following configurations.

     apiVersion: cert-manager.io/v1
     kind: Certificate
     metadata:
       name: nginxweb.example.com
       namespace: default
     spec:
       secretName: nginxweb.example.com-tls
       issuerRef:
         name: letsencrypt-prod
         kind: ClusterIssuer
       commonName: nginxweb.example.com
       dnsNames:
       - nginxweb.example.com
  4. Apply the above configuration to the cluster.

     # kubectl apply -f letsencrypt-certificate.yml

    This will create a Traefik Ingress Let's Encrypt TLS certificate for the domain nginxweb.example.com.

     certificate.cert-manager.io/nginxweb.example.com created
  5. Verify the created certificate.

     # kubectl get certificates nginxweb.example.com 

    Sample output.

     NAME                    READY   SECRET                      AGE
     nginxweb.example.com   True    nginxweb.example.com-tls   55s

Define Let's Encrypt Certificate in Traefik Ingress Resource

After creating Traefik Ingress Let's Encrypt SSL, define the certificate in traefik-ingress.yml.

Edit the traefik-ingress.yml using the nano editor.

# KUBE_EDITOR= "nano" kubectl edit ingress traefik-ingress

Change the file with the following configuration.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: traefik
  creationTimestamp: "2022-11-26T14:32:09Z"
  generation: 1
  name: traefik-ingress
  namespace: default
  resourceVersion: "2125"
  uid: 942404bd-6031-4a31-9f89-eccbc66b80f6
spec:
  rules:
  - host: nginxweb.example.com
    http:
      paths:
      - backend:
          service:
            name: nginx-web
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - nginxweb.example.com
    secretName: nginxweb.example.com-tls

status:
  loadBalancer: {}

Verify HTTPS

Your Nginx website is now deployed on the Kubernetes cluster with Let's Encrypt SSL. You can now verify it by visiting the URL https://nginxweb.example.com in your web browser. You can also verify the Nginx website using curl.

# curl -L https://nginxweb.example.com

Conclusion

You have deployed an Nginx website with cert-manager, Traefik, and Let's Encrypt SSL on Vultr Kubernetes Engine. You can also deploy and serve many websites on the same cluster using different Ingress resources. For more information, visit the Traefik Proxy documentation page.