This project provisions a small but realistic Azure infrastructure using Terraform.
The goal of the project is to demonstrate practical cloud engineering skills by deploying a Linux virtual machine in Azure with:
- Infrastructure as Code
- custom networking
- security rules
- SSH-based access
- automated nginx installation through cloud-init
After deployment, the VM is reachable through SSH and serves a basic web page over HTTP.
The infrastructure includes:
- Azure Resource Group
- Azure Virtual Network
- Azure Subnet
- Azure Public IP
- Azure Network Security Group
- inbound rules for SSH and HTTP
- Azure Network Interface
- Azure Linux Virtual Machine
- cloud-init bootstrap for nginx
Terraform creates the following resources:
azurerm_resource_groupazurerm_virtual_networkazurerm_subnetazurerm_public_ipazurerm_network_security_groupazurerm_network_security_ruleazurerm_network_interfaceazurerm_network_interface_security_group_associationazurerm_linux_virtual_machine
The VM is configured with:
- Ubuntu 22.04 LTS ARM64
- SSH key authentication
- password authentication disabled
- nginx installed automatically via cloud-init
- Terraform
- Microsoft Azure
- Azure CLI
- Linux
- SSH
- cloud-init
- nginx
This project demonstrates:
- Infrastructure as Code with Terraform
- Azure networking fundamentals
- subnetting and IP space configuration
- basic cloud security with NSG rules
- Linux VM provisioning
- SSH key management
- automated instance bootstrap with cloud-init
- troubleshooting real deployment issues in Azure
Before deploying this project, make sure you have:
- an active Azure subscription
- Terraform installed
- Azure CLI installed
- an SSH public key available locally
- permission to create Azure resources in the target subscription
The project uses Terraform variables for reusable configuration.
Example values are provided in terraform.tfvars.example.
A local terraform.tfvars file is expected for real deployments.
Example:
project_name = "cloudlab"
environment = "dev"
location = "germanywestcentral"
vnet_address_space = ["10.0.0.0/16"]
subnet_address_prefixes = ["10.0.1.0/24"]
admin_username = "azureuser"
ssh_public_key_path = "C:/Users/your-user/.ssh/azure_vm_ed25519.pub"
vm_size = "Standard_B2pts_v2"- Initialize Terraform:
terraform init- Review formatting and validate configuration:
terraform fmt
terraform validate- Preview the deployment
terraform plan- Apply the infrastructure:
terraform apply- After deployment, retrieve useful values with:
terraform output- SSH into the virtual machine:
ssh -i ~/.ssh/azure_vm_ed25519 azureuser@<public-ip>- Then open the VM public IP in a browser
http://<public-ip>
You should see the nginx page generated through cloud-init.
├── provider.tf
├── variables.tf
├── locals.tf
├── main.tf
├── network.tf
├── security.tf
├── compute.tf
├── outputs.tf
├── cloud-init.yaml
├── terraform.tfvars.example
├── .gitignore
└── README.md
During development, two realistic Azure deployment issues came up:
- Some VM sizes were not available in the selected region and subscription.
- The initially selected VM image was x64, while the available VM SKU required ARM64.
The final solution was to use an ARM64-compatible Ubuntu image with an ARM64-compatible Azure VM size.
This reflects a real-world cloud engineering scenario where deployment constraints depend on both regional SKU availability and CPU architecture compatibility.
Future improvements for this project could include:
- using Terraform modules
- adding Azure tags for governance
- restricting SSH access to a trusted public IP
- adding monitoring with Azure Monitor
- introducing CI/CD with GitHub Actions
- replacing manual local key handling with a more advanced secret-management approach
I built this project to strengthen my hands-on cloud engineering skills alongside my university studies and Azure certification path.
The focus was not only to provision resources, but to understand how networking, security, Linux administration, and automation fit together in a realistic Azure deployment.