DevOps
Terraform Basics
Learn Infrastructure as Code with Terraform. Understand providers, resources, state management, and creating your first infrastructure.
By TechCoder TeamLast updated: 2026-06-02
In a Nutshell
Learn Infrastructure as Code with Terraform. Understand providers, resources, state management, and creating your first infrastructure. This hands-on tutorial focuses on practical implementation of terraform basics concepts.
Terraform Basics
Terraform is an open-source Infrastructure as Code tool that enables you to define and provision infrastructure using a declarative configuration language.
Why Terraform?
┌─────────────────────────────────────────────────────────────────┐
│ Infrastructure as Code │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Manual (Click-Ops) ──────> Terraform (IaC) │
│ │
│ ❌ Slow ✅ Fast automated provisioning │
│ ❌ Error-prone ✅ Consistent, repeatable │
│ ❌ No history ✅ Version controlled │
│ ❌ Hard to replicate ✅ Same code for all environments │
│ ❌ Documentation ✅ Self-documenting │
│ │
└─────────────────────────────────────────────────────────────────┘
Terraform Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Terraform Workflow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Terraform Configuration (.tf files) │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ terraform │────>│ terraform │────>│ terraform │ │
│ │ init │ │ plan │ │ apply │ │
│ │ │ │ │ │ │ │
│ │ • Download │ │ • Refresh │ │ • Create/ │ │
│ │ providers │ │ • Compare │ │ Update/ │ │
│ │ • Setup │ │ • Show │ │ Destroy │ │
│ │ modules │ │ execution │ │ resources │ │
│ │ • Initialize │ │ plan │ │ │ │
│ │ backend │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────┐ │
│ │ │ State File │ │
│ │ │ (terraform. │ │
│ │ │ tfstate) │ │
│ │ └──────────────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Providers │ │
│ │ (AWS/Azure/ │ │
│ │ GCP/etc) │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Installation and Setup
# Install Terraform (macOS)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# Linux
wget https://releases.hashicorp.com/terraform/1.6.0/terraform_1.6.0_linux_amd64.zip
unzip terraform_1.6.0_linux_amd64.zip
sudo mv terraform /usr/local/bin/
# Verify
terraform -version
# Enable autocomplete
terraform -install-autocomplete
Terraform Configuration
File Structure
project/
├── main.tf # Main configuration
├── variables.tf # Variable definitions
├── outputs.tf # Output values
├── providers.tf # Provider configuration
├── terraform.tfvars # Variable values (gitignored)
├── versions.tf # Provider version constraints
└── modules/ # Reusable modules
└── vpc/
├── main.tf
├── variables.tf
└── outputs.tf
Basic Configuration
# providers.tf
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = var.project_name
}
}
}
# variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_count" {
description = "Number of EC2 instances"
type = number
default = 2
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
# main.tf
# Data source for latest Amazon Linux AMI
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
# VPC Module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "${var.environment}-vpc"
cidr = "10.0.0.0/16"
azs = ["${var.aws_region}a", "${var.aws_region}b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = var.environment != "prod"
tags = {
Terraform = "true"
}
}
# Security Group
resource "aws_security_group" "web" {
name_prefix = "${var.environment}-web-"
description = "Allow HTTP/HTTPS inbound traffic"
vpc_id = module.vpc.vpc_id
ingress {
description = "HTTP from anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
description = "Allow all outbound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
}
# EC2 Instances
resource "aws_instance" "web" {
count = var.instance_count
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
subnet_id = module.vpc.public_subnets[count.index % length(module.vpc.public_subnets)]
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y nginx
systemctl start nginx
systemctl enable nginx
echo "<h1>Server ${count.index + 1}</h1>" > /usr/share/nginx/html/index.html
EOF
tags = {
Name = "${var.environment}-web-${count.index + 1}"
}
}
# outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = module.vpc.vpc_id
}
output "public_subnet_ids" {
description = "IDs of public subnets"
value = module.vpc.public_subnets
}
output "instance_ips" {
description = "Public IPs of EC2 instances"
value = aws_instance.web[*].public_ip
}
output "web_urls" {
description = "URLs to access web servers"
value = [for ip in aws_instance.web[*].public_ip : "http://${ip}"]
}
Terraform Commands
# Initialize (download providers, setup backend)
terraform init
# Validate configuration
terraform validate
# Format code
terraform fmt
terraform fmt -recursive
# Generate execution plan
terraform plan
terraform plan -out=tfplan
# Apply changes
terraform apply
terraform apply tfplan
terraform apply -auto-approve
# Destroy infrastructure
terraform destroy
# Show state
terraform show
terraform state list
terraform state show aws_instance.web[0]
# Import existing resources
terraform import aws_instance.web i-1234567890abcdef0
# Refresh state (reconcile with real infrastructure)
terraform refresh
# Taint resource (force recreate)
terraform taint aws_instance.web[0]
# Workspaces (multiple environments)
terraform workspace new staging
terraform workspace select staging
terraform workspace list
State Management
Remote State (S3 + DynamoDB)
# State locking with DynamoDB
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
State Commands
# Pull state
curl -o terraform.tfstate $(terraform state pull)
# Push state
terraform state push terraform.tfstate.backup
# Remove resource from state (don't destroy)
terraform state rm aws_instance.web[0]
# Move resource in state
terraform state mv aws_instance.old aws_instance.new
Quiz
Quiz
Question 1 of 5What command initializes a Terraform working directory?
terraform start
terraform init
terraform setup
terraform prepare
Next Steps
Now let's explore advanced Terraform concepts: modules, workspaces, and remote state.