Skip to main content

Command Palette

Search for a command to run...

Terraform From Zero to Advanced: A Beginner-Friendly Guide

Updated
8 min read
Terraform From Zero to Advanced: A Beginner-Friendly Guide
A

🚀 𝐀𝐛𝐨𝐮𝐭 𝐌𝐞 "Hi, I'm Ali masiu zama, a DevOps student passionate about cloud computing and automation. I'm currently learning AWS, Linux, Docker, and CI/CD pipelines, with a focus on automating workflows and building scalable solutions.

Introduction

Terraform is one of the most powerful tools for Infrastructure as Code (IaC). It allows you to create, change, and manage cloud resources using simple configuration files. Whether you're deploying an EC2 instance, an S3 bucket, or an entire VPC, Terraform makes everything repeatable, automated, and error‑free.

This guide will walk you through Terraform from absolute basics to advanced concepts in the simplest possible way.

Table of Contents

  1. What is Terraform?

  2. Why Terraform?

  3. How Terraform Works

  4. Terraform Architecture

  5. Providers

  6. Arguments & Meta‑Arguments

  7. Modules

  8. Remote Backends

  9. Workspaces

  10. Terraform Lifecycle

  11. Provisioners

  12. Data Sources

  13. Common Terraform Commands

  14. Terraform Code – Create an EC2 Instance

  15. Terraform Code – Create an S3 Bucket

  16. Terraform Code – Create a VPC, Subnet, IGW, Route Table (Basic Setup)

  17. Conclusion

1. What is Terraform?

Terraform is an Infrastructure as Code tool that lets you define cloud resources (AWS, Azure, GCP, etc.) in .tf files using simple syntax. Instead of clicking buttons in the console, you write code.

Terraform reads this configuration and creates the infrastructure exactly as described.

2. Why Terraform?

  • Automation: No manual setup.

  • Consistency: Same setup everywhere.

  • Multi‑Cloud: Supports almost all cloud platforms.

  • Version Control: You can track changes in Git.

  • Reusable: Write once, reuse multiple times with modules.

3. How Terraform Works

Terraform follows a simple workflow:

  1. Write (.tf files)

  2. Initialize (terraform init)

  3. Validate (terraform validate)

  4. Plan (terraform plan)

  5. Apply (terraform apply)

  6. Destroy (terraform destroy)

Terraform takes your desired state (what you wrote) and matches it with actual state (what exists), then applies changes.

4. Terraform Architecture

Terraform is made of:

ComponentsPurpose (Explanation)
Core EngineReads your .tf files, compares desired vs. actual state, and creates an execution plan.
ProvidersPlugins that allow Terraform to interact with cloud/platform APIs (AWS, Azure, GCP, GitHub, Kubernetes, etc.).
State FileStores information about real resources so Terraform knows what already exists and what needs changes.
BackendDetermines where the state file is stored (local machine, S3 bucket, Terraform Cloud, etc.).

Install Terraform (Linux – Ubuntu/Debian)

sudo apt update
sudo apt install -y gnupg software-properties-common

wget -O- https://apt.releases.hashicorp.com/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt update
sudo apt install -y terraform

Check version:

terraform -version

5. Providers

  • Providers are plugins that teach Terraform how to talk to a cloud or service.
    It knows how to create, update, delete, and manage resources for a specific platform.

Example providers include:

  • AWS

  • Azure

  • Google Cloud

  • GitHub

  • Kubernetes

  • Docker

Each provider contains the logic + API calls needed to manage resources.

  • Why Terraform Needs Providers?

Terraform itself does NOT know how to:

  • create an EC2 instance

  • create an S3 bucket

  • create a VPC

  • update an IAM policy

All of this knowledge comes from the provider plugin.

So Terraform acts like the “brain,”
and the provider is the “hands” that perform the actual API calls.

Example:

provider "aws" {
  region     = "us-west-2"
  access_key = "my-access-key"
  secret_key = "my-secret-key"
}

Terraform automatically downloads providers during terraform init.

  • Terraform provider Documentation say

  1. Providers are the bridge between Terraform and the actual service API.

  2. Providers support resources (things you create or manage).

  3. Providers support data sources (things you read from the cloud).

  4. Providers can be configured once or multiple times.

  5. Providers are downloaded via terraform init.

6. Arguments & Meta‑Arguments

Arguments

Regular properties inside a resource.

Example:

ami           = "ami-123456"
instance_type = "t2.micro"

Meta‑Arguments

Special features Terraform gives you:

  • count

  • for_each

  • depends_on

count

  • Used to create multiple copies of the same resource.

  • Uses a number (0, 1, 2, …).

  • Good for conditional creation (count = 0 = don’t create).

Example:

count = 2

Creates 2 resources.

for_each (Create multiple resources using names/keys)

for_each is used when you want to create multiple resources, and each item has its own identity (name, key, tag, etc.).

Why use for_each?

  • Creates resources based on a map or set

  • Gives stable names (unlike count, where indexes can shift)

  • Best when each resource has a unique key

Example

resource "aws_instance" "servers" {
  for_each = {
    dev  = "t2.micro"
    prod = "t2.small"
  }

  instance_type = each.value
  tags = {
    Name = each.key
  }
}

This creates 2 EC2 instances:
✔ One named dev
✔ One named prod

depends_on (Force resource ordering)

depends_on tells Terraform:
👉 "Create this only after another resource is done."

Terraform usually detects dependencies automatically, but sometimes you must force it.

Why use depends_on?

  • When Terraform cannot detect connection

  • When resources are logically connected but not referenced directly

  • Ensures proper ordering

Example

resource "aws_s3_bucket" "logs" {
  bucket = "my-logs-bucket"
}

resource "aws_iam_role" "role" {
  name = "logging-role"

  depends_on = [aws_s3_bucket.logs]   # Wait for bucket
}

The IAM role waits until the S3 bucket is created.

7. Modules (Reusable Terraform components)

Modules allow you to organize Terraform code and reuse it.

Why use modules?

  • Clean folder structure

  • Reusable templates

  • Production-ready design

  • Easier maintenance

Example: Module Folder Structure

modules/
  ec2/
    main.tf
    variables.tf
    outputs.tf

Calling the module

module "my_ec2" {
  source = "./modules/ec2"
  instance_type = "t2.micro"
}

Modules are like functions

You write code once → use many times.

9. Remote Backends

A backend is where Terraform stores the state file.

Remote backends make Terraform state:

Safe
Shareable
Locked (so two people cannot run Terraform at the same time)
Version-controlled

➡️ AWS S3 + DynamoDB (for state locking)

Example Backend Configuration

terraform {
  backend "s3" {
    bucket         = "mytfbucket"
    key            = "state/dev.tfstate"
    region         = "ap-south-1"
    dynamodb_table = "tf-state-lock"
  }
}

What this does:

  • Stores state in S3 bucket

  • Locks state using DynamoDB

  • Prevents two DevOps engineers from running terraform apply at the same time

This is a must for production.

10. Workspaces

Workspaces let you run multiple environments (dev, stage, prod) using the same Terraform code.

Why workspaces?

You don’t need separate folders or duplicate files.

Example:

  • dev

  • stage

  • prod

Each workspace gets its own state file, like:

terraform.tfstate.d/dev/terraform.tfstate
terraform.tfstate.d/prod/terraform.tfstate

Commands:

terraform workspace new dev                      #Create a workspace
terraform workspace select dev                   #Switch workspace
terraform workspace list                         #List all workspaces

11. Terraform Lifecycle

Controls special behaviors of a resource.
It has 4 important sub-options:

1. Init (terraform init)

Downloads the required provider plugins and prepares the working directory.

2. Plan (terraform plan)

Shows what Terraform will create, update, or delete — a preview before making changes.

3. Apply (terraform apply)

Executes the plan and actually creates or updates the infrastructure.

4. Destroy (terraform destroy)

Deletes the infrastructure that Terraform created.

Example:

terraform init                                    # Initialize
terraform plan                                    # See what will happen
terraform apply                                   # Create resources
terraform destroy                                 # Destroy everything

12. Provisioners

Used to run scripts or commands after a resource is created.

Types:

  • local-exec → run on your laptop

  • remote-exec → run on EC2 or server

  • file → copy files to server

Example:

provisioner "remote-exec" {
  inline = ["sudo apt update"]
}

Use provisioners only when absolutely necessary.

13. Data Sources

Data sources help you fetch existing information.

Example:

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]
}

14. Common Terraform Commands

terraform init                                    # Initialize
terraform validate                                # Validate syntax
terraform plan                                    # See what will happen
terraform apply                                   # Create resources
terraform destroy                                 # Destroy everything
terraform destroy -target=aws_s3_bucket.my_bucket    # Destroy specific resource
terraform state list                              # Check all managed resources

15. Terraform Code – Create an EC2 Instance

Create a file: ec2.tf

provider "aws" {
  region = "ap-south-1"
  access_key = "my-access-key"
  secret_key = "my-secret-key"
}

resource "aws_instance" "my_ec2" {
  ami           = "ami-0c2b8ca1dad447f8a"        # (Ubuntu image)
  instance_type = "t2.micro"

  tags = {
    Name = "my-ec2-instance"                     # Your server name which you will create.
  }
}

Commands:

terraform init                                    # Initialize
terraform validate                                # Validate syntax
terraform plan                                    # See what will happen
terraform apply                                   # Create resources

16. Terraform Code – Create an S3 Bucket

Create a file: s3.tf

provider "aws" {
  region = "ap-south-1"
  access_key = "my-access-key"
  secret_key = "my-secret-key"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "ali-demo-bucket-12345"              # bucket name must be unique globally
tags = {
    Name        = "My bucket"
    Environment = "Dev"                 # It is a custom tag used to identify the environment in which this resource is used."
  }
}

17. Terraform Code – Create a VPC, Subnet, IGW, Route Table (Basic Setup)

Create file: vpc.tf

# AWS Provider Configuration

provider "aws" {
  region     = "ap-south-1"                 # AWS region (Mumbai)
  access_key = "my-access-key"              # Your AWS access key
  secret_key = "my-secret-key"              # Your AWS secret key
}

resource "aws_vpc" "main_vpc" {
  cidr_block = "10.0.0.0/16"            # Main network range for VPC

  tags = {
    Name = "main-vpc"                   # Name tag for identification
  }
}


resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.main_vpc.id       # Attach subnet to VPC
  cidr_block              = "10.0.1.0/24"             # Subnet range
  map_public_ip_on_launch = true                      # Auto-assign public IP

  tags = {
    Name = "public-subnet"                            # Tag for subnet
  }
}


resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main_vpc.id                   # Attach IGW to VPC

  tags = {
    Name = "main-igw"                            # Name tag
  }
}


resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.main_vpc.id                       # Attach RT to VPC

  route {
    cidr_block = "0.0.0.0/0"                         # All traffic
    gateway_id = aws_internet_gateway.igw.id         # Send to IGW
  }

  tags = {
    Name = "public-route-table"   # Tag for route table
  }
}

# Route Table Association
# Connect Subnet → Route Table

resource "aws_route_table_association" "public_rt_assoc" {
  subnet_id      = aws_subnet.public_subnet.id                   # Which subnet?
  route_table_id = aws_route_table.public_rt.id                  # Which route table?
}

18. Conclusion

Terraform is simple but powerful. By mastering resources, variables, modules, state, backends, and advanced concepts, you can manage any cloud infrastructure with confidence.

Use this guide as your foundation and keep practicing by building real projects like VPCs, EC2 setups, multi-tier architectures, and automated modules.

More from this blog

DevOpsAlimasiuzama

30 posts