Tools: Terraform Basics: Manage Your Infrastructure as Code in 30 Minutes
Terraform Basics: Manage Your Infrastructure as Code in 30 Minutes
Why Infrastructure as Code
Install Terraform
Your First Terraform Config (DigitalOcean Droplet)
State Management
Practical Example: Full Stack (Droplet + Firewall + Domain)
Essential Terraform Commands If you're still managing servers by clicking through cloud consoles — this is for you. Terraform lets you define your entire infrastructure in code. Reproducible, version-controlled, reviewable. Terraform tracks what it's created in a state file. For teams, store state remotely: I built ARIA to solve exactly this.
Try it free at step2dev.com — no credit card needed. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
# Mac
-weight: 500;">brew tap hashicorp/tap && -weight: 500;">brew -weight: 500;">install hashicorp/tap/terraform # Ubuntu/Debian
-weight: 500;">wget -O- https://-weight: 500;">apt.releases.hashicorp.com/gpg | -weight: 600;">sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://-weight: 500;">apt.releases.hashicorp.com $(lsb_release -cs) main" | -weight: 600;">sudo tee /etc/-weight: 500;">apt/sources.list.d/hashicorp.list
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install terraform terraform --version
# Mac
-weight: 500;">brew tap hashicorp/tap && -weight: 500;">brew -weight: 500;">install hashicorp/tap/terraform # Ubuntu/Debian
-weight: 500;">wget -O- https://-weight: 500;">apt.releases.hashicorp.com/gpg | -weight: 600;">sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://-weight: 500;">apt.releases.hashicorp.com $(lsb_release -cs) main" | -weight: 600;">sudo tee /etc/-weight: 500;">apt/sources.list.d/hashicorp.list
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install terraform terraform --version
# Mac
-weight: 500;">brew tap hashicorp/tap && -weight: 500;">brew -weight: 500;">install hashicorp/tap/terraform # Ubuntu/Debian
-weight: 500;">wget -O- https://-weight: 500;">apt.releases.hashicorp.com/gpg | -weight: 600;">sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://-weight: 500;">apt.releases.hashicorp.com $(lsb_release -cs) main" | -weight: 600;">sudo tee /etc/-weight: 500;">apt/sources.list.d/hashicorp.list
-weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install terraform terraform --version
# main.tf
terraform { required_providers { digitalocean = { source = "digitalocean/digitalocean" version = "~> 2.0" } }
} provider "digitalocean" { token = var.do_token
} variable "do_token" { description = "DigitalOcean API token" sensitive = true
} resource "digitalocean_droplet" "web" { name = "web-server-1" region = "nyc3" size = "s-1vcpu-1gb" image = "ubuntu-22-04-x64" ssh_keys = [digitalocean_ssh_key.default.fingerprint] tags = ["web", "production"]
} resource "digitalocean_ssh_key" "default" { name = "my-key" public_key = file("~/.ssh/id_ed25519.pub")
} output "droplet_ip" { value = digitalocean_droplet.web.ipv4_address
}
# main.tf
terraform { required_providers { digitalocean = { source = "digitalocean/digitalocean" version = "~> 2.0" } }
} provider "digitalocean" { token = var.do_token
} variable "do_token" { description = "DigitalOcean API token" sensitive = true
} resource "digitalocean_droplet" "web" { name = "web-server-1" region = "nyc3" size = "s-1vcpu-1gb" image = "ubuntu-22-04-x64" ssh_keys = [digitalocean_ssh_key.default.fingerprint] tags = ["web", "production"]
} resource "digitalocean_ssh_key" "default" { name = "my-key" public_key = file("~/.ssh/id_ed25519.pub")
} output "droplet_ip" { value = digitalocean_droplet.web.ipv4_address
}
# main.tf
terraform { required_providers { digitalocean = { source = "digitalocean/digitalocean" version = "~> 2.0" } }
} provider "digitalocean" { token = var.do_token
} variable "do_token" { description = "DigitalOcean API token" sensitive = true
} resource "digitalocean_droplet" "web" { name = "web-server-1" region = "nyc3" size = "s-1vcpu-1gb" image = "ubuntu-22-04-x64" ssh_keys = [digitalocean_ssh_key.default.fingerprint] tags = ["web", "production"]
} resource "digitalocean_ssh_key" "default" { name = "my-key" public_key = file("~/.ssh/id_ed25519.pub")
} output "droplet_ip" { value = digitalocean_droplet.web.ipv4_address
}
# Initialize (downloads provider plugins)
terraform init # Preview what will be created
terraform plan # Apply (creates the resources)
terraform apply # Destroy when done
terraform destroy
# Initialize (downloads provider plugins)
terraform init # Preview what will be created
terraform plan # Apply (creates the resources)
terraform apply # Destroy when done
terraform destroy
# Initialize (downloads provider plugins)
terraform init # Preview what will be created
terraform plan # Apply (creates the resources)
terraform apply # Destroy when done
terraform destroy
terraform { backend "s3" { bucket = "my-terraform-state" key = "production/terraform.tfstate" region = "us-east-1" # Enable state locking dynamodb_table = "terraform-locks" encrypt = true }
}
terraform { backend "s3" { bucket = "my-terraform-state" key = "production/terraform.tfstate" region = "us-east-1" # Enable state locking dynamodb_table = "terraform-locks" encrypt = true }
}
terraform { backend "s3" { bucket = "my-terraform-state" key = "production/terraform.tfstate" region = "us-east-1" # Enable state locking dynamodb_table = "terraform-locks" encrypt = true }
}
resource "digitalocean_droplet" "app" { name = "app-server" region = "nyc3" size = "s-2vcpu-2gb" image = "ubuntu-22-04-x64" ssh_keys = [digitalocean_ssh_key.default.fingerprint]
} resource "digitalocean_firewall" "app" { name = "app-firewall" droplet_ids = [digitalocean_droplet.app.id] inbound_rule { protocol = "tcp" port_range = "22" source_addresses = ["YOUR_IP/32"] # SSH only from your IP } inbound_rule { protocol = "tcp" port_range = "80" source_addresses = ["0.0.0.0/0", "::/0"] } inbound_rule { protocol = "tcp" port_range = "443" source_addresses = ["0.0.0.0/0", "::/0"] } outbound_rule { protocol = "tcp" port_range = "all" destination_addresses = ["0.0.0.0/0", "::/0"] }
} resource "digitalocean_domain" "app" { name = "yourdomain.com" ip_address = digitalocean_droplet.app.ipv4_address
}
resource "digitalocean_droplet" "app" { name = "app-server" region = "nyc3" size = "s-2vcpu-2gb" image = "ubuntu-22-04-x64" ssh_keys = [digitalocean_ssh_key.default.fingerprint]
} resource "digitalocean_firewall" "app" { name = "app-firewall" droplet_ids = [digitalocean_droplet.app.id] inbound_rule { protocol = "tcp" port_range = "22" source_addresses = ["YOUR_IP/32"] # SSH only from your IP } inbound_rule { protocol = "tcp" port_range = "80" source_addresses = ["0.0.0.0/0", "::/0"] } inbound_rule { protocol = "tcp" port_range = "443" source_addresses = ["0.0.0.0/0", "::/0"] } outbound_rule { protocol = "tcp" port_range = "all" destination_addresses = ["0.0.0.0/0", "::/0"] }
} resource "digitalocean_domain" "app" { name = "yourdomain.com" ip_address = digitalocean_droplet.app.ipv4_address
}
resource "digitalocean_droplet" "app" { name = "app-server" region = "nyc3" size = "s-2vcpu-2gb" image = "ubuntu-22-04-x64" ssh_keys = [digitalocean_ssh_key.default.fingerprint]
} resource "digitalocean_firewall" "app" { name = "app-firewall" droplet_ids = [digitalocean_droplet.app.id] inbound_rule { protocol = "tcp" port_range = "22" source_addresses = ["YOUR_IP/32"] # SSH only from your IP } inbound_rule { protocol = "tcp" port_range = "80" source_addresses = ["0.0.0.0/0", "::/0"] } inbound_rule { protocol = "tcp" port_range = "443" source_addresses = ["0.0.0.0/0", "::/0"] } outbound_rule { protocol = "tcp" port_range = "all" destination_addresses = ["0.0.0.0/0", "::/0"] }
} resource "digitalocean_domain" "app" { name = "yourdomain.com" ip_address = digitalocean_droplet.app.ipv4_address
}
terraform init # Initialize project
terraform plan # Preview changes
terraform apply # Apply changes
terraform destroy # Destroy all resources
terraform show # Show current state
terraform output # Show outputs
terraform fmt # Format .tf files
terraform validate # Validate config syntax
terraform init # Initialize project
terraform plan # Preview changes
terraform apply # Apply changes
terraform destroy # Destroy all resources
terraform show # Show current state
terraform output # Show outputs
terraform fmt # Format .tf files
terraform validate # Validate config syntax
terraform init # Initialize project
terraform plan # Preview changes
terraform apply # Apply changes
terraform destroy # Destroy all resources
terraform show # Show current state
terraform output # Show outputs
terraform fmt # Format .tf files
terraform validate # Validate config syntax - "I'm not sure what settings I used on the production server"
- Can't recreate your setup if the server dies
- No audit trail for infrastructure changes - Your entire infra is a -weight: 500;">git repo
- Recreate production in 10 minutes
- Review infrastructure changes like code reviews