DEV Community

Ezekiel Olaniyan
Ezekiel Olaniyan

Posted on

Provisioning a Functional Virtual Machine with Terraform on Azure

Infrastructure as Code (IaC) has become an important practice in modern cloud engineering because it allows infrastructure to be defined, deployed, and managed using configuration files rather than manually creating resources through a cloud provider's user interface.
As part of my journey into Cloud and DevOps Engineering, I worked on a hands-on project to provision a functional Azure Virtual Machine (VM) using Terraform.
In this project, I created the required Azure infrastructure, deployed a functional Linux virtual machine, installed Nginx, configured a remote Terraform backend, and pushed the configuration to GitHub.
This article documents the process and some of the lessons I learned along the way.

What I Built
The project involved provisioning the following Azure resources using Terraform:
• Resource Group
• Virtual Network
• Subnet
• Public IP Address
• Network Security Group (NSG)
• Network Interface Card (NIC)
• Virtual Machine
• Nginx web server
• Azure Storage Account
• Azure Storage Container for Terraform remote state
The overall objective was to move from manually creating infrastructure to defining and managing it as code.

Step 1: Initializing the Terraform Configuration
The first step was to create a dedicated working directory for the Terraform project.
I created a folder named:
terraform-demo2
inside my Documents directory.
I then created a Terraform configuration file called:
main.tf
The main.tf file contains the Terraform configuration used to define the infrastructure that I wanted Azure to provision.
After creating the configuration, I initialized Terraform using:
terraform init

Step 2: Planning and Applying the Terraform Configuration
After initializing Terraform, I developed the infrastructure configuration in main.tf.
The configuration defined the infrastructure starting from the resource group and networking components through to the virtual machine.
The resources included:
Resource Group

Virtual Network

Subnet

Public IP

Network Security Group

Network Interface

Virtual Machine
I also configured Terraform to output the public IP address of the virtual machine after deployment.
Running Terraform Plan
Before creating the infrastructure, I used:
terraform plan
The terraform plan command allowed me to review the changes Terraform intended to make before actually creating the resources.
This is an important step because it provides an opportunity to identify configuration errors or unexpected changes before they affect the Azure environment.
Applying the Configuration
After reviewing the plan, I deployed the infrastructure using:
terraform apply
Terraform then communicated with Azure and created the resources defined in the configuration.
Once the deployment was completed successfully, the required Azure resources were available for use.

Step 3: Successfully Provisioning a Functional Virtual Machine
One of the most exciting parts of the project was seeing the virtual machine successfully provisioned and become functional.
The VM was created with the networking components required to allow connectivity.
After deployment, I connected to the VM and installed Nginx, which I used to verify that the web server was running successfully.
Nginx can be installed on an Ubuntu-based Linux VM using:
sudo apt update
sudo apt install nginx -y
After installing Nginx, I checked the service:
sudo systemctl status nginx
The service was running successfully.
I then accessed the VM through its public IP address from a web browser.
Seeing the Nginx welcome page confirmed that the VM was not only created successfully but was also functioning as a web server.

Step 4: Reviewing the Provisioned Resources in Azure
After Terraform completed the deployment, I checked the Azure Portal to verify the resources that had been created.
The resources included the components required to support the virtual machine, such as:
• Resource Group
• Virtual Network
• Subnet
• Public IP
• Network Security Group
• Network Interface
• Virtual Machine
This provided a useful visual confirmation that the infrastructure defined in Terraform had been successfully translated into actual Azure resources

Step 5: Creating and Configuring a Remote Backend
After successfully provisioning the VM, I moved to another important Terraform concept: remote state management.
Terraform uses a state file to keep track of the infrastructure it manages.
Instead of keeping the Terraform state only on my local computer, I configured an Azure Storage Account and Blob Container to serve as a remote backend.
The Azure resources required for this included:
Storage Account

Blob Container

Terraform Remote State
I created the storage account and container using Azure CLI commands.
The Terraform backend configuration was then added to the Terraform configuration.

Step 6: Pushing the Terraform Configuration to GitHub
After configuring the remote backend, I created a Git repository for the project.
I initialized Git using:
git init
I then created a .gitignore file.
The purpose of the .gitignore file was to prevent files that should not be committed to the repository from being tracked by Git.
For example, Terraform projects commonly need to exclude files such as:
.terraform/
.tfstate
*.tfstate.

It is important to understand that Terraform state files can contain sensitive infrastructure information, so they should be handled carefully.
I then staged the relevant files:
git add main.tf .gitignore
and committed them:
git commit -m "Add Terraform Azure VM configuration"
Because my GitHub repository used the main branch, I changed the local branch to main before pushing:
git branch -M main
I then connected the local repository to GitHub and pushed the configuration:
git push -u origin main
The Terraform configuration and .gitignore file were successfully pushed to my GitHub repository.

Terraform Configuration in GitHub
The project files were now available in my GitHub repository.
The repository contained the Terraform configuration and supporting files required for the project.
[Insert Screenshot: main.tf and .gitignore in GitHub]
The remote backend configuration was also reflected in the Terraform project.

Conclusion
This project gave me practical experience provisioning a functional Azure Virtual Machine using Terraform.
Starting with a simple main.tf file, I was able to define and provision the required Azure infrastructure, deploy a functional Linux VM, install Nginx, configure a remote Terraform backend, and version-control the project using Git and GitHub.
More importantly, the project helped me understand how different Cloud and DevOps technologies fit together:
Terraform

Azure Infrastructure

Linux Virtual Machine

Nginx

Azure Remote Backend

Git & GitHub

CI/CD Automation
For me, this project represents another practical step toward becoming a well-grounded Cloud and DevOps Engineer.

CloudComputing #DevOps #Terraform #Azure #InfrastructureAsCode #IaC #GitHub #Linux #Nginx #CloudEngineering #DevOpsEngineering

Top comments (5)

Collapse
 
4thman profile image
David Cletus

This is lovely

Collapse
 
prayo25 profile image
Ezekiel Olaniyan

Thanks bro

Collapse
 
ayoola07 profile image
Ayoola Gabriel

Great steps all resources included from resource group down to the last step. Well done 👍

Collapse
 
prayo25 profile image
Ezekiel Olaniyan

Thank you bro.

Collapse
 
ayoola07 profile image
Ayoola Gabriel

Great steps all resources included from resource group down to the last step. Well done 👍``