Learn Terraform – How can we make the Linux VM become a Web Server

The next iteration of the VM is to configure a Web Server running on the VM and add an auto-scaling function as well as a load balancer. Due to the point, that I’m not so aware of Linux, I took a little bit different approach to have a Web Server running on the VM. Yevgeniy uses in his book the following “user_data” option to have a web site been served by our VM.

user_date = <<-EOF
            #!/bin/bash
            echo "Hellom, World" > index.html
            nohup busybox httpd -f -p 8080 &
            EOF

I tried to get this as a script running in the VM just deployed. But I did not find out what will be the best way. So maybe this is a challenge for later, but take it the other way around, what is the normal Way in Azure to get something running in a VM just deployed. I normally use the custom script extensions to run a command in a machine. Especially in a Windows VM I would use any desired state configuration with this option. If you want to learn more about custom script extension focusing on a Linux VMs visit this DOCs article.

With this knowledge we now can add a section in our script to deploy a custom script extension:

resource "azurerm_virtual_machine_extension" "myFirstTerraform" {
  name = "myFirstTerraform-Script"
  virtual_machine_id = azurerm_linux_virtual_machine.myFirstTerraform.id
  publisher = "Microsoft.Azure.Extensions"
  type = "CustomScript"
  type_handler_version ="2.0"

  settings = <<SETTINGS
    {
      "commandToExecute" : "apt-get -y update && apt-get install -y apache2" 
    }
    SETTINGS
 }

The important configuration is made in the settings section. I added the command to install an apache web server on the machine and then we will have the standard website been served in port 80 on the Linux VM. The only trouble we get is, our network security group (NSG) we deployed, was only opening the ssh port. So we must add an additional rule in the NSG. So our NSG will look like this:

 resource "azurerm_network_security_group" "myFirstTerraform" {
    name                = "myFirstTerraform"
    location            = azurerm_resource_group.myFirstTerraform.location
    resource_group_name = azurerm_resource_group.myFirstTerraform.name

    security_rule {
        name                       = "SSH"
        priority                   = 1001
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "22"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
     }

     security_rule {
        name                       = "WebServer"
        priority                   = 1002
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "80"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
     }
}

If we now would run our script, we will be able to see the default apache web site on our Linux VM running in Azure:

Default apache website

To connect to this website it would be great to know on which public IP assigned to our Linux VM. As we learn in the book, we can use the output variables to achieve this. But there is one important difference. In Azure, a public IP is a resource on his own and will be attached to a network interface that then will be assigned to a VM. So we need to reference the IP in our output and not the VM.

What does that mean for our script:

output "public_ip" {
   value       = azurerm_public_ip.myFirstTerraform.ip_address
   description = "This is the asigned public ip to our VM"
}

If we have added this output to our script we can afterwards just get the ip after you apply your script again:

$ terraform apply

Outputs:

public_ip = 51.136.162.193

If you need the output of your latest terrafrom deployment again you just can call:

$ terraform output public_ip

51.136.162.193

So now you know the ip to browse to, if you want to see your apache 2 default webiste.