Building and Deploying a Portfolio Website on Azure Static Web Apps with Terraform and GitHub Actions

JyothishJyothish
7 min read

I wanted to find a way to practice my Azure and Terraform skills. What better way than to build a production-ready website and finally put my theoretical knowledge into action?

My main goal was to learn how to use Terraform to deploy resources to Azure. However, along the way, I picked up more useful tools and skills than I expected, from generating frontends with AI to setting up a basic CI/CD pipeline using GitHub Actions.

By the end of this blog, you'll learn how I:

  • Deployed my portfolio website meetjyothish.com to Azure Static Web Apps using Terraform.

  • Integrated my Static Web App with GitHub repository and set up a streamlined CI/CD pipeline using GitHub Actions and the Azure CLI.

  • Created a clean and modern frontend with lovable.dev.

  • Utilized VS Code and GitHub Copilot to build the website to be a production ready portfolio.

In my next blog post, I’ll walk through how I integrated Azure Functions into my site to track visitor counts. I’ll also show how I used an Azure Function to handle a contact form, which sends the submitted details to my email via the Mailersend API whenever someone requests an interview. Lastly, I’ll explain how I set up real-time notifications for new visitor IPs and locations using Azure Functions in combination with the ipinfo API.

If you want to try this, check out this link to sign up for Lovable AI and start building your portfolio.

Affiliate link - https://lovable.dev/?via=jyothish


Generating a Frontend with Lovable.dev

I wanted to make sure my portfolio website was running locally before deploying anything to Azure. I had heard about a few AI-based website generators, and after trying a couple, I found that lovable.dev gave me the cleanest UI out of the box.

I signed up for the free version (since I wasn't planning to scale the website or make anything super complex) and started working on my first prompt.

Pro Tip: Lovable.dev only gives you 5 prompts per day — so make them count. I didn’t realize this at first and burned through them quickly. I had to work with the result I got, which meant I spent quite a bit of time later tweaking the frontend to fit my needs 😅.

Instead of deep diving into prompt engineering guides, I just opened Notepad and wrote down what I wanted my website to look like. Then, I asked ChatGPT to turn that into a proper prompt for Lovable.AI.

Here’s an example of the prompt it helped me create:

“Help me create a professional and sleek portfolio web app. I will attach my resume for reference to build the content around my experience and skills. The overall design should reflect a modern vibe, but still remain clean, simple, and visually attractive.”

Sections & Features I Asked For:

  • Hero section: My name, a headline, and a short summary

  • About Me section

  • Projects: With GitHub links and project descriptions

  • Contact: A simple form or mailto link

  • Dark/Light mode toggle

  • Responsive design (mobile + desktop)

  • Modern fonts like Inter or Roboto

  • Clean code structure so I could edit it later

Once you’re happy with the results on Lovable, you still have 4 prompts left per day, so feel free to use them to tweak layout, copy, or fix issues. Once satisfied, click the GitHub icon at the top right, choose “Connect GitHub,” and follow the steps. This will create a new GitHub repo and push the full codebase there.

After that, clone the repo to your local machine using VS Code and start fine-tuning the website to fit your exact needs. If you prefer to continue working with Lovable website, you can do so with further prompts. But i decided to do the rest of dev on my own locally.


Setting Up the Local Dev Environment in VS Code

The code generated by Lovable was written in React, so before making any changes, I had to:

  • Install Node.js and npm

  • Set up the local development environment using Vite (as the build tool and dev server)

  • Run the project locally using npm run dev

Once I had the site running locally, I started cleaning up unnecessary Lovable artifacts. For example:

  • The favicon and branding used the default Lovable logo ,I replaced this with a simple logo I created for my site.

  • I rewrote index.html to include custom meta tags for social previews, so when I shared my website link, it would show my own branding.

  • I used GitHub Copilot to help me identify and clean up parts of the code, though at one point it broke the layout , so I rolled back the changes using Git revert.

Pro Tip:

Track all your changes with Git! It saved me more than once when Copilot made suggestions that seemed right but didn’t work as expected.

Once I finished cleaning things up, I asked Copilot to do a quick pass through the code and flag any potential security issues. I'm not a full-time web dev, so I wanted to make sure I wasn't exposing anything critical . especially since I might integrate APIs or backend services later.

After I was satisfied with my website locally, I proceeded to work on my Terraform code to deploy it to Azure Static Web Apps using GitHub Actions. I ensured that I had the following installed:

  • Azure CLI

  • Terraform

  • Active subscription ID and tenant ID

To log in to your Azure subscription, use the following command:

az login

Once logged in, I developed the following code. Refer to the Terraform registry if you plan to deploy something else.

main.tf

resource "azurerm_resource_group" "rg" {
  name     = "rg-${var.application_name}-${var.environment_name}"
  location = var.primary_location
}

resource "azurerm_static_web_app" "webapp" {
  name                = "WebApp-${var.application_name}-${var.environment_name}"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  repository_url      = "your github url"
  repository_branch   = "main"
  repository_token    = var.github_token
}

Note: It is recommended to use environment variables for tokens and tenant ID/subscription ID if you plan to do this in production.

terraform.tfvars

application_name = "portfolio"
environment_name = "Prod"
primary_location = "centralus"
github_token     = "github_yourtoken"
subscription_id  = "yoursubid"
tenant_id        = "yoursubtenantid"

versions.tf

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.30.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.5.1"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = var.subscription_id
}

variables.tf

variable "application_name" {
  type = string
}

variable "environment_name" {
  type = string
}

variable "primary_location" {
  type = string
}

variable "github_token" {
  type        = string
  description = "GitHub Personal Access Token for repository access"
}

variable "subscription_id" {
  type = string
}

variable "tenant_id" {
  type        = string
  description = "Azure Tenant ID"
}

# NOTE: Ensure sensitive information like your Azure Subscription ID, Tenant ID, and GitHub Tokens 
# are NOT hardcoded in your Terraform files or checked into version control. Instead, use 
# environment variables or a secure vault (e.g., Azure Key Vault, HashiCorp Vault) to store these values

After installing Terraform, run the following commands:

terraform init
terraform plan
terraform apply

This will create your Azure Static Web App. You can log in to the Azure portal at portal.azure.com to verify that your web app is live. You will receive a fully qualified domain name (FQDN) that you can use to view the site online.

Note: After deploying with Terraform, my Static Web App didn’t automatically create a GitHub Actions workflow, likely due to a missing or invalid repository_token. To fix this, I manually ran the following command to link the GitHub repo and generate the workflow file:

az staticwebapp update --name WebApp-portfolio-Prod --branch main --source https://github.com/yourpath-to/repo --token ghh-yorutoken --output jsonc

This created a YAML file in GitHub repository under .github/workflows. This file is used by GitHub Actions to define CI/CD pipeline.

At this point, if the YAML file automatically created by Azure is correct, it should automatically build and deploy your website to Azure Static Web Apps. I encountered an issue where it couldn't find the location of my code because I was using Vite, and my app_artifact_location was dist.

app_artifact_location: dist

After adding this to the YAML file, it proceeded to run my actions, and my website was live. after this i could make changes, and every changes were reflected on my Production site, after i commit changes to my remote repo, since Github Actions will automatically deploy the changed code for me.

0
Subscribe to my newsletter

Read articles from Jyothish directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jyothish
Jyothish