Published on

🌍🚀🎯 From Localhost to Cloud ☁️: Next.js, Django, SSL 🔒, Github Actions 🚀, DNS Configuration | The Ultimate Website Deployment Tutorial with Kubernetes 🌟🔥✨



Table of Contents


Picture this: 📸 You have developed a stunning website, and now it's time to make it accessible to the world. But the deployment process seems daunting, right? 😰

Fear not, because Kubernetes is here to save the day. 🦸‍♂️ With its powerful features and intelligent container management, Kubernetes takes the complexity out of website deployment.

In this tutorial, we will demystify Kubernetes and guide you through the process of deploying your website effortlessly. Get ready to unlock the magic of Kubernetes and witness your website thrive in realms of the Cloud. ✨🌐

What we will do

We will guide you through the process of deploying your website from running locally on your localhost to the Cloud.

The website will be a full stack website with frontend and backend with a SQLite database served over SSL.

We will also make a CI Pipeline to deploy code on commit to master Branch.

To accomplish this, we will perform the following steps:

  • Dockerize the Next.js frontend and Django backend.
  • Write Kubernetes manifests for frontend and backend servers, including a Persistent Volume for the Django SQLite database and obtaining an SSL certificate using Cert Manager.
  • Create a Kubernetes cluster in GCP.
  • Configure the domain's DNS.
  • Write GitHub Actions YAML for building and deploying applications to GCP.
  • Push code to GitHub for deployment.

This tutorial involves several technologies, and if you encounter any unfamiliar concepts, don't worry. As you progress through the tutorial, you will gain a better understanding of each technology and its role in the deployment process.


To successfully complete this tutorial, you will need:

  • A GCP Account
  • A Domain Name

If you haven't purchased a domain name yet, I recommend using Namecheap as I have personally used them and had a good experience.

I highly recommend to read through the tutorial 2-3 times before proceeding with the deployment on your own.


For this tutorial, a repository has been created consisting of two folders: frontend and backend.

The frontend folder contains the code for the Next.js-based application, while the backend folder contains the code for the Django-based application.

To begin, you will need to clone the starter code:

git clone

Open the project in Visual Studio Code by running:

code kubernetes-website-deployment-tutorial-starter/

Dockerizing Frontend

To Dockerize the frontend code built with Next.js, create a Dockerfile in the frontend folder with the following contents:


FROM node:16-alpine

COPY package.json .
RUN rm -rf node_modules/ .next/* && npm install --legacy-peer-deps
COPY . .

RUN npm run build

CMD ["npm", "run", "start"]

Additionally, create a .dockerignore file in the frontend folder with the same contents as .gitignore by running following command:

cp frontend/.gitignore frontend/.dockerignore

Dockerizing Backend

Now, let's Dockerize the Django-based backend code by creating a Dockerfile in the backend folder with the following contents:


FROM python:3.9

COPY requirements.txt .
RUN python -m pip install -r requirements.txt

RUN mkdir app
COPY . /app

CMD gunicorn --workers 3 -b config.wsgi

Next, create a .dockerignore file in the backend folder with the same contents as .gitignore by running following command:

cp backend/.gitignore backend/.dockerignore

Creating PVC for Backend

To ensure persistence of our SQLite database file used in the Django application, let's create a Persistent Volume Claim (PVC) by creating pvc.yaml file at k8s/volumes/ with the following contents, which provisions 4GB of storage in GCP:


apiVersion: v1
kind: PersistentVolumeClaim
  name: csi-pvc
    - ReadWriteOnce
      storage: 4Gi
  storageClassName: standard-rwo

Creating Service for Backend and Frontend

To make the backend and frontend pods accessible within the cluster, create the following manifest files:

  1. Backend Deployment (k8s/app/backend-depl.yaml):
apiVersion: apps/v1
kind: Deployment
  name: backend-depl
  replicas: 1
      app: backend
        app: backend
        - name: app-data
            claimName: csi-pvc
        - name: backend
          image: placeholder/backend:1.0.5
            - mountPath: /app-data
              name: app-data
apiVersion: v1
kind: Service
  name: backend-srv
    app: backend
    - name: backend
      protocol: TCP
      port: 8000
      targetPort: 8000
  1. Frontend Deployment (k8s/app/frontend-depl.yaml):
apiVersion: apps/v1
kind: Deployment
  name: frontend-depl
  replicas: 1
      app: frontend
        app: frontend
        - name: frontend
              ephemeral-storage: "800Mi"
              ephemeral-storage: "800Mi"
          image: placeholder/frontend:1.0.4
apiVersion: v1
kind: Service
  name: frontend-srv
    app: frontend
    - name: frontend
      protocol: TCP
      port: 3000
      targetPort: 3000

Creating Load Balancer

To expose our pods via services, we need to create an Ingress resource. Create a file named ingress.yaml in k8s/app/ with the following contents, replacing "" with your domain name:


kind: Ingress
  name: ingress-service
  annotations: nginx "letsencrypt-prod" 80m "30" "600" "600"
    - host: ""
          - path: /backend
            pathType: Prefix
                name: backend-srv
                  number: 8000
          - path: /
            pathType: Prefix
                name: frontend-srv
                  number: 3000

    - hosts:
        - ""
      secretName: ssl-certificate

Getting SSL Certificate

To obtain an SSL certificate for your domain, you can create a YAML file named certificates.yaml in the k8s/certificates directory.

Replace with your actual domain name and optionally replace with your email address to receive SSL-related emails from Let's Encrypt (Our SSL Provider).


kind: Issuer
  name: letsencrypt-prod
      name: letsencrypt-prod
      - http01:
            class: nginx
            - ""

Create Github Actions

To automate the deployment process of your application on each commit to the master branch, you can utilize GitHub Actions.

The following workflow defines the necessary steps to authenticate with Google Cloud Platform (GCP), build Docker images, push them to Google Container Registry, and deploy the application to Google Kubernetes Engine (GKE) cluster.

Please note that the deployment includes deleting the previous backend deployment, which will result in temporary downtime of 4 to 5 minutes whenever you deploy code by pushing to Github.

We also utilize various Google Cloud Platform (GCP) environment variables for the deployment, which we will store securely in the secrets of our GitHub repository later.

To use this workflow create a file called deploy.yaml in the .github/workflows directory. Here is the content for the deploy.yaml file:


name: Build and Deploy to GKE

      - master

  PROJECT_ID: ${{ secrets.GKE_PROJECT }}
  GKE_CLUSTER: my-application-cluster
  GKE_PROJECT: ${{ secrets.GKE_PROJECT }}
  GKE_CLUSTER_NAME: my-application-cluster
  GKE_ZONE: asia-south1-a
  GKE_EMAIL: ${{ secrets.GKE_EMAIL }}
  GKE_KEY: ${{ secrets.GKE_KEY }}
  GITHUB_SHA: ${{ github.sha }}

    name: Setup, Build, Publish, and Deploy
    runs-on: ubuntu-latest
    environment: production
      contents: 'read'
      id-token: 'write'

      - name: Checkout
        uses: actions/checkout@v3

      - name: Set Images as enviroment variables
        run: |
          echo "FRONTEND=$(echo """$GKE_PROJECT""/frontend:""$GITHUB_SHA")" >> $GITHUB_ENV
          echo "BACKEND=$(echo """$GKE_PROJECT""/backend:""$GITHUB_SHA")" >> $GITHUB_ENV

      - name: update images
        run: |
          FRONTEND_ESCAPE=$(printf '%s\n' "$FRONTEND" | sed -e 's/[\/&]/\\&/g')
          sed -i -e 's/placeholder\/frontend:1.0.4/'"$FRONTEND_ESCAPE"'/g' frontend-depl.yaml
          cat frontend-depl.yaml
          BACKEND_ESCAPE=$(printf '%s\n' "$BACKEND" | sed -e 's/[\/&]/\\&/g')
          sed -i -e 's/placeholder\/backend:1.0.5/'"$BACKEND_ESCAPE"'/g' backend-depl.yaml
          cat backend-depl.yaml
        working-directory: k8s/app

      - id: 'auth'
        uses: 'google-github-actions/auth@v1'
          credentials_json: '${{ secrets.GCP_CREDENTIALS }}'

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v1

      - name: Install Gke
        run: |
          gcloud components install gke-gcloud-auth-plugin

      - name: Cluster Login
        run: |
          gcloud container clusters get-credentials $GKE_CLUSTER_NAME --zone $GKE_ZONE --project $GKE_PROJECT

      - name: Configure Docker
        run: gcloud --quiet auth configure-docker

      - run: docker build --tag "$FRONTEND" .
        working-directory: frontend

      - run: docker build --tag "$BACKEND" .
        working-directory: backend

      - name: Push Images
        run: |
          docker push "$FRONTEND"
          docker push "$BACKEND"

      - name: Deploy
        run: |
          kubectl delete deployment backend-depl || true
          kubectl apply --recursive -f k8s/
          deploy=$(kubectl get deploy -o name) &&  for i in $deploy; do kubectl rollout status $i -w --timeout=30s; done || true
          kubectl get pods

GCP Setup

Now, we will set up the GCP Cluster. I will tell you when there you need to change some variables. Please only modify the variables I tell you and keep the other variables untouched, such as the cluster name and zone etc.

As they are hardcoded and will be used multiple times in the commands of this Tutorial. Once you have become familiar with the tutorial, feel free to rename them according to your preference.

  1. Enable the following APIs for your Project to create a GKE cluster:
Artifact Registry:
Kubernetes Engine:
Compute Engine:


  1. In the sidebar, click on the "Kubernetes Engine" button.


  1. Click on the "Create" button to create a new cluster. Configure the "Standard Mode" Cluster, as it is more cost-effective.


  1. Provide the following details for the cluster:
Cluster Name: my-application-cluster
Location Type: zonal
Zone: asia-south1-a


  1. In the sidebar, select "default-pool" and change the number of nodes to 1 instead of 3 to save costs.


  1. In the sidebar, select "Nodes" and use the following settings to save costs:
Machine Type: e2-small 
Boot Disk Size: 20 GB 


The estimated cost should be around $90. If this is your first cluster in GCP, the cost will be charged around $27 after 1 Month discounting $73 discount for the first cluster.

  1. Click the "Create" button, and the cluster will be created in approximately 5-6 minutes.

  2. Open the GCP Shell by clicking the shell icon in the top-right corner.


  1. Authenticate in your cluster by running the following command. Replace "clear-world-31478" with your GCP project name.
gcloud container clusters get-credentials my-application-cluster --zone asia-south1-a --project clear-world-31478
  1. Create an IP address by running the following command:
gcloud compute addresses create my-application-cluster-ip --region asia-south1
  1. Note the created IP address by running the command:
gcloud compute addresses describe my-application-cluster-ip --region asia-south1
  1. In your Domain Name Service (DNS) provider, such as Namecheap, add the following records. Replace "" with the IP address obtained in the previous step.
A @
A www

Ensure that the TTL (Time to Live) is set to the lowest possible value, such as 1 minute, to allow for fast DNS propagation.

If you are using Namecheap, select the 1-minute TTL option, which will take 1 minute to propogate DNS Changes.

  1. Execute the following commands to install ingress-nginx and cert-manager which are needed do load balancing get the SSL certificate. In the following commands, replace with the IP address you created earlier.
helm repo add ingress-nginx
helm upgrade --install ingress-nginx-chart ingress-nginx/ingress-nginx --set controller.service.loadBalancerIP= --set controller.service.externalTrafficPolicy=Local

helm repo add jetstack
helm repo update
kubectl apply -f
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.8.0

Github Setup

This is the final step where we will configure GitHub Secrets for our deployment workflow and push the code.

  1. Create a Github Repository

  2. Create a service account JSON file by visiting The service account will have full access to all resources (Owner) in Google Cloud (GCP). Keep the JSON file secure, as it will be required for deploying to Google Kubernetes Engine (GKE). Save the file as account.json.


  1. Create Github secrets which are used in Workflow by going to your Repository GitHub Settings > Secrets > Actions and creating three secrets with the following names and values:


  • GKE_PROJECT is your project name.
  • GKE_EMAIL is email located in the account.json file.
  • GKE_KEY is your service account encoded as base64. You can obtain it by running cat account.json | base64.
  1. Now, push the code to the repository. Once pushed, the site will be ready 4-5 minutes after the GitHub Action is completed. It takes 4-5 minutes as it will obtain SSL certificates etc.

You can view status of your actions by visiting Action Tabs of your Github Repository.

After Action is Completed, you can access the website at your domain.

Delete the Resources

Remember to delete the GCP resources to avoid incurring charges. Follow these steps to delete the GCP resources:

  1. Delete the created IP address by running the following command. In this command, replace "clear-world-31478" with your GCP project name.
gcloud compute addresses delete my-application-cluster-ip --region asia-south1 --project clear-world-31478
  1. Use the GKE Dashboard to delete the cluster using the graphical user interface.


Q: How can I connect PostgreSQL to Django in Kubernetes?

A: If you are just starting out, I highly recommend using SQLite to save both money and development time. However, if you prefer to use PostgreSQL, you can follow the tutorial at

Q: Where is the final Code?

A: You can find the final code at

Final Words

Congratulations on successfully deploying your website! You have accomplished website deployment with SSL, DNS, GitHub Actions, etc.

If you have any questions, feel free to ask them in the comments.

Also, this article is licensed under MIT, so you are free to use it as you wish.

If you are a YouTuber, I encourage you to create a video of this article on your channel. By doing so, you can potentially help thousands of developers solve their deployment problems and earn great amounts of punya. Additionally, you can send me your Video URL and I will feature your video at the top of the article, boosting its views.

Time is Money Friend. So in case you want hire a Ninja Kubernetes Developer to perform Deployment for your Project, Contact me at