Skip to content

Infrastructure tools · guide

Infrastructure as code with OpenTofu

7 min read · Last checked 10 October 2026

The course’s labs build their machines in Microsoft Azure with a tool called OpenTofu. This page explains what the tool does and what each of its commands is for. You don’t need to know how to code to follow it.

Infrastructure is the set of machines and networks that a system runs on. In the course, most of it is virtual machines: computers that run as software on Microsoft’s hardware in Azure, Microsoft’s cloud service. You rent them by the hour instead of buying and looking after physical computers.

You can build a virtual machine by clicking through the Azure Portal, Azure’s website. That works, but it’s hard to repeat exactly, and nothing records what you clicked.

Infrastructure as code means you describe the machines in text files instead, and a tool builds them from those files. The files say what should exist, not the steps to make it. OpenTofu calls this set of files a configuration. Because it’s plain text, you can read it and build from it again.

OpenTofu is a tool that reads a configuration and builds what it describes. You type its commands in a terminal (see What a terminal is), and every command starts with the word tofu.

OpenTofu can’t reach Azure by itself. It uses providers: add-on programs that let it manage one platform. The course uses the Azure provider called azurerm, which manages Azure virtual machines, networks and storage.

A resource is one thing the configuration describes, such as one network or one virtual machine. The block below is written in OpenTofu’s own file language. It’s shortened from the course’s Module 3 files and describes an Azure resource group: a named group in Azure that holds related resources. When you delete a resource group, Azure deletes everything in it.

resource "azurerm_resource_group" "lab" {
name = var.resource_group_name
location = "eastus"
}

The first line names the kind of resource and gives it a label, lab. The lines inside set the group’s name and its Azure region, the part of the world whose Microsoft data centres hold it: here East US. var.resource_group_name stands for the value of the variable called resource_group_name.

A variable is a named setting that the configuration leaves open, so each person can fill in their own value without editing the configuration. The course’s variables include these:

  • Your Azure subscription ID: the ID of the Azure account that pays.
  • Your SSH public key. SSH is the way you log in to a remote Linux machine from a terminal. It uses a key pair: two matching keys, a private one that stays on your computer and a public one you put on the machine.
  • A short name of your choosing that goes into each machine’s web address.

You set the values in a .tfvars file, a short text file of lines in the form name = "value". OpenTofu reads a file called terraform.tfvars in the folder automatically. Each lab folder comes with terraform.tfvars.example, which the first lab step copies to terraform.tfvars for you to fill in.

Your terraform.tfvars is never shared. It holds your settings: your subscription, your key and, in one module, an admin password. The course’s labs repository, its folder of lab files on GitHub, is set up so this file is never saved into its shared history. Don’t post it or send it to anyone.

You can also set one variable for one command with -var. In Module 7, the fleet machines are the course’s Ubuntu Linux client machines. The lab starts with one, then grows the fleet to three with tofu apply -var fleet_count=3.

  1. tofu init prepares the folder and downloads the providers the configuration needs. It’s safe to run more than once.
  2. tofu plan compares the configuration with what already exists and lists what it would add, change or destroy. It changes nothing.
  3. tofu apply carries out a plan. Run on its own, it makes a fresh plan, shows it, and waits for you to type yes.
  4. tofu destroy removes everything this configuration built. It’s another way to write tofu apply -destroy, so it also shows the plan and waits for yes. Machines left running cost money, so the labs tear them down between sessions.

A plan ends with a summary line, such as Plan: 21 to add, 0 to change, 0 to destroy. Read it every time. If you expected only additions and it says something will be destroyed, stop and find out why.

In Module 7, fleet_count is 1 unless you say otherwise. If three fleet machines already exist from an earlier tofu apply -var fleet_count=3, a later apply without -var fleet_count=3 plans to destroy two of them.

The course reads every plan first, in one of two ways:

  • Modules 3 to 9 use tofu apply and tofu destroy on their own. Each shows its plan and waits, so read the plan before you type yes.
  • From Module 10 on, the labs save the plan to a file first. tofu plan -out <file> saves the plan and prints it. After you read it, tofu apply <file> carries out exactly the actions in that file. Tearing down works the same way, with tofu plan -destroy -out <file> and then tofu apply <file>.

When you give apply a saved plan, it doesn’t ask again: the saved file counts as your approval. The OpenTofu docs warn that a saved plan file can hold sensitive values in plain text, so the labs delete it right after applying it.

To know what it built, OpenTofu keeps state: a record that links each resource in the configuration to the real object in Azure. By default it’s a file called terraform.tfstate in the same folder.

Keep state private. The docs describe local state as plain-text files that hold every setting of every resource, which can include passwords, and they say to treat state as sensitive. The labs repository never saves state files into its shared history. Keep the file in its folder, too: OpenTofu needs it to match your configuration to what exists in Azure.

The OpenTofu commands, in orderThe lab folder holds the configuration (the text files), your settings in terraform.tfvars, which fill in the variables and are never shared, and the state file terraform.tfstate, which you keep private. In order: tofu init downloads the providers; tofu plan lists what would change and changes nothing, ending with a line such as Plan: 21 to add, 0 to change, 0 to destroy, which you read every time; tofu apply builds in Azure after you type yes. tofu destroy removes everything it built, after you type yes. The state links each resource to its real object in Azure. LAB FOLDERCONFIGURATIONthe text filesYOUR SETTINGSterraform.tfvarsnever sharedfills inthe variablesSTATEterraform.tfstatekeep it privateAZUREwhat gets built1tofu initdownloadsthe providers2tofu planlists what wouldchange; changesnothing3tofu applybuilds afteryou type yesPlan: 21 to add, 0 to change, 0 to destroyread this line every time4tofu destroyremoves everything it built,after you type yeslinks each resource to its real object
The four commands in order, the plan line to read, and the two files that stay private.

An output is a value the configuration reports back after it builds something, such as a machine’s web address. Outputs print at the end of tofu apply, not after tofu plan. tofu output shows them again later.

OpenTofu started as a fork (a separately developed copy) of Terraform, HashiCorp’s infrastructure-as-code tool, after HashiCorp changed Terraform’s licence. It aims to stay compatible with Terraform configurations, and in this course the commands are the same with terraform in place of tofu. That’s also why the files are still called terraform.tfvars and terraform.tfstate.

Command What it does
Copy-Item terraform.tfvars.example terraform.tfvars Makes your own copy of the example settings file to fill in (cp instead of Copy-Item on macOS or Linux).
tofu init Prepares the folder and downloads the providers the configuration needs.
tofu plan Shows what would be added, changed or destroyed, and changes nothing.
tofu plan -out <file> Saves the plan to a file with any name you choose, such as lab.tfplan, so you can read it and then apply exactly that.
tofu apply <file> Carries out a saved plan, without asking again.
Remove-Item <file> Deletes the saved plan file once it’s applied, because it can contain secrets (rm on macOS or Linux).
tofu apply Makes a fresh plan, shows it, and builds only after you type yes.
tofu apply -var <name>=<value> Sets one variable for this run only, such as fleet_count=3.
tofu apply -replace <address> Removes one resource and builds it again. The address is the resource’s name as the plan prints it, such as azurerm_linux_virtual_machine.fleet["02"]. In Module 7 the -var must come along, and in PowerShell the address goes in single quotes with \" inside: tofu apply -var fleet_count=3 -replace 'azurerm_linux_virtual_machine.fleet[\"02\"]'.
tofu output Lists every output value, such as the machines’ web addresses.
tofu output -raw <name> Prints one output value on its own, ready to copy.
tofu plan -destroy -out <file> Saves a plan that removes everything this folder built, so you can read it before you apply it.
tofu destroy Shows a plan to remove everything this folder built, and removes it after you type yes.

Sources

Facts on this page are explained in our own words. Short quotes are marked and linked.