Skip to main content

Command Palette

Search for a command to run...

🚀Day 4 – Automate Static Website Deployment Using Terraform

Azure Zero to Hero Series

Updated
4 min read
🚀Day 4 – Automate Static Website Deployment Using Terraform

Welcome to Day 4 of the Azure Zero to Hero series!
Today’s focus is on Infrastructure as Code (IaC) - Terraform.

You’ll learn:

  • Automate deployments

  • Version control your infrastructure

  • Reusing terraform templates

Step1: Install and configure Azure CLI

az login

Step2: Create a service principal

az ad sp create-for-rbac --name "terraform-sp" --role="Contributor" --scopes="/subscriptions/xx" --sdk-auth

Note: In place of xx in the above command replace your subscription id

Step3: Create terraform files

Open gitbash

mkdir createvm_azure
cd createvm_azure
touch cloud-init.txt variables.tf provider.tf main.tf terraform.tfvars outputs.tf
vi cloud-init.txt

#cloud-config
package_update: true
package_upgrade: true
packages:
  - nginx
  - wget
  - unzip

runcmd:
  - systemctl enable nginx
  - systemctl start nginx
  - wget -O /tmp/lugx_temp.zip https://templatemo.com/download/templatemo_589_lugx_gaming
  - unzip -q /tmp/lugx_temp.zip -d /var/www/
  - mv /var/www/templatemo_589_lugx_gaming/* /var/www/html/
  - rm -rf /tmp/lugx_temp.zip /var/www/templatemo_589_lugx_gaming
  - chown -R www-data:www-data /var/www/html
  - chmod -R 755 /var/www/html
  - systemctl restart nginx
vi variables.tf
variable "subscription_id" {
  type        = string
  description = "Azure Subscription ID"
}

variable "location" {
  type        = string
  description = "Azure Region"
  default     = "eastus"
}

variable "resource_group" {
  type        = string
  description = "Azure resource group name"
}

variable "vnet_name" {
  type        = string
  description = "Azure Virtual Network Name"
}

variable "subnet_name" {
  type        = string
  description = "Azure Subnet Name"
}

variable "vm_name" {
  type        = string
  description = "Azure Virtual Machine Name"
}

variable "vm_username" {
  type        = string
  description = "Admin Username for the Virtual Machine"
}

variable "vm_password" {
  type        = string
  description = "Admin Password for the Virtual Machine"
  sensitive   = true
}

variable "custom_data_file" {
  type        = string
  description = "Path to custom data file"
  default     = "cloud-init.txt"
}
vi provider.tf
provider "azurerm" {
  features {}
  subscription_id = var.subscription_id
}
vi main.tf
resource "azurerm_resource_group" "main" {
  name     = var.resource_group
  location = var.location
}

resource "azurerm_virtual_network" "main" {
  name                = var.vnet_name
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_subnet" "main" {
  name                 = var.subnet_name
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = ["10.0.0.0/24"]
}

resource "azurerm_network_security_group" "main" {
  name                = "${var.vm_name}-nsg"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_network_security_rule" "allow_ssh" {
  name                        = "allow-ssh"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "22"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  network_security_group_name = azurerm_network_security_group.main.name
  resource_group_name         = azurerm_resource_group.main.name
}

resource "azurerm_network_security_rule" "allow_http" {
  name                        = "allow-http"
  priority                    = 200
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "80"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  network_security_group_name = azurerm_network_security_group.main.name
  resource_group_name         = azurerm_resource_group.main.name
}

resource "azurerm_public_ip" "main" {
  name                = "${var.vm_name}-pip"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  allocation_method   = "Static"
  sku                 = "Standard"
}

resource "azurerm_network_interface" "main" {
  name                = "${var.vm_name}-nic"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.main.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.main.id
  }

}

resource "azurerm_network_interface_security_group_association" "example" {
  network_interface_id      = azurerm_network_interface.main.id
  network_security_group_id = azurerm_network_security_group.main.id
}

resource "azurerm_linux_virtual_machine" "main" {
  name                            = var.vm_name
  resource_group_name             = azurerm_resource_group.main.name
  location                        = azurerm_resource_group.main.location
  size                            = "Standard_B1s"
  admin_username                  = var.vm_username
  admin_password                  = var.vm_password
  disable_password_authentication = false

  network_interface_ids = [
    azurerm_network_interface.main.id,
  ]

  custom_data = base64encode(file(var.custom_data_file))

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    name                 = "${var.vm_name}-osdisk"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts"
    version   = "latest"
  }
}
vi terraform.tfvars
subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
location        = "eastus"
resource_group  = "web-rg"
vnet_name       = "web-vnet"
subnet_name     = "web-subnet"
vm_name         = "testservervm"
vm_username     = "testuser"
vm_password     = "SecUrePwd@Az!$#"
custom_data_file = "cloud-init.txt"
vi outputs.tf
output "vm_public_ip" {
  description = "Public IP address of the virtual machine"
  value       = azurerm_public_ip.main.ip_address
}

output "ssh_username" {
  value = var.vm_username
}

output "web_url" {
  value = "http://${azurerm_public_ip.main.ip_address}"
}
# Initialize
terraform init

# Validate
terraform validate

# Plan
terraform plan

# Apply
terraform apply -auto-approve

🧠 Tip

If you get any error related to vm sizes, check with bellow command

az vm list-sizes --location eastus -o table

Access the url on browser

Step4: Clean Up Resources

terraform destroy -auto-approve

More from this blog

thiru's blog

43 posts