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 to Azure Static Web Apps using Terraform. (Note: this was my original site — it has since been rebuilt and replaced with the current version.)
- Integrated my Static Web App with GitHub 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 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, handle a contact form via the Mailersend API, and set up real-time notifications for new visitor IPs using the ipinfo API.
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 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.
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, 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.
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:
- Replaced the default Lovable favicon/branding with a simple logo I created for my site.
- Rewrote
index.htmlto include custom meta tags for social previews. - Used GitHub Copilot to identify and clean up parts of the code — though at one point it broke the layout, so I rolled back 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.
After I was satisfied with the website locally, I also asked Copilot to do a quick pass through the code and flag any potential security issues — especially important since I planned to integrate APIs and backend services later.
Deploying to Azure with Terraform
Once the frontend was ready, I moved on to writing Terraform code to deploy it to Azure Static Web Apps.
Prerequisites
- Azure CLI
- Terraform
- Active Azure Subscription ID and Tenant ID
Log in to your Azure subscription:
az login
Terraform Configuration
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
}
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"
}
terraform.tfvars (never commit this to version control)
application_name = "portfolio"
environment_name = "Prod"
primary_location = "centralus"
github_token = "github_yourtoken"
subscription_id = "yoursubid"
tenant_id = "yoursubtenantid"
Note: It is strongly recommended to use environment variables or a secure vault (e.g., Azure Key Vault, HashiCorp Vault) for sensitive values like tokens and IDs in production. Never hardcode them or check them into version control.
Running Terraform
terraform init
terraform plan
terraform apply
This will create your Azure Static Web App. You can verify it’s live in the Azure portal at portal.azure.com. You’ll receive a fully qualified domain name (FQDN) to access the site.
Setting Up GitHub Actions CI/CD
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-yourtoken \
--output jsonc
This created a YAML file in your repository under .github/workflows/. This file defines your CI/CD pipeline and is used by GitHub Actions to automatically build and deploy your site.
One Gotcha with Vite
I hit an issue where GitHub Actions couldn’t find my built output because I was using Vite. The fix was simple — set the app_artifact_location in the YAML:
app_artifact_location: dist
After adding that, the pipeline ran successfully and my website went live. From that point on, every commit to the main branch automatically triggers a build and deploys the updated code to Azure Static Web Apps.
That’s the full setup. With Terraform handling the infrastructure and GitHub Actions handling deployments, I now have a production-ready portfolio with a proper CI/CD pipeline — all built as a hands-on learning project.