Infrastructure as Code with Terraform
Infrastructure as Code with Terraform
Section titled “Infrastructure as Code with Terraform”Infrastructure as Code (IaC) means describing your servers, networks, and cloud resources in version-controlled files instead of clicking through consoles. Terraform is the most widely used IaC tool: you declare the desired end state, and Terraform figures out the create/update/delete actions to reach it. The result is reproducible, reviewable, and auditable infrastructure.
Core concepts and workflow
Section titled “Core concepts and workflow”- Providers — plugins that talk to a platform’s API (AWS, Cloudflare, Proxmox, etc.).
- Resources — the things you declare (
resource "cloudflare_record" "www" { ... }). - Data sources — read existing infrastructure you don’t manage.
- State — Terraform’s record of what it has created, mapping config to real resources.
The loop is write → plan → apply:
terraform init # download providers, configure the backendterraform plan # show what will change — review this like a diffterraform apply # make it so (after confirmation)terraform destroy # tear it all downterraform { required_providers { cloudflare = { source = "cloudflare/cloudflare", version = "~> 4" } }}
resource "cloudflare_record" "www" { zone_id = var.zone_id name = "www" type = "CNAME" content = "example.pages.dev" proxied = true}State management
Section titled “State management”State is the most dangerous part of Terraform. Local state (terraform.tfstate on
one laptop) breaks the moment a second person runs apply — concurrent runs corrupt
state and drift from reality. Use a remote backend with locking:
terraform { backend "s3" { bucket = "my-tf-state" key = "prod/terraform.tfstate" region = "us-east-1" dynamodb_table = "tf-locks" # state locking — prevents concurrent applies encrypt = true }}State often contains secrets (generated passwords, keys) in plaintext — encrypt the
backend, restrict access, and never commit *.tfstate to git.
Modules
Section titled “Modules”A module is a reusable, parameterized group of resources — inputs (variable), outputs
(output), and the resources between them. Write a module when you’d otherwise
copy-paste a block of resources; pull common ones from the
Terraform Registry.
module "site" { source = "./modules/static-site" zone_id = var.zone_id domain = "example.com"}Multi-environment patterns
Section titled “Multi-environment patterns”Keep dev/staging/prod from stepping on each other:
| Approach | How | When |
|---|---|---|
| Workspaces | terraform workspace new staging — one config, separate state per workspace | Small differences, same shape |
| Separate state per env | A directory + backend key per environment | Real isolation; the safer default for prod |
| Terragrunt | Wrapper that keeps backend/provider blocks DRY across many envs | Many environments/accounts |
Workspaces are tempting but share one config and backend, so a mistake can hit prod. For anything where blast radius matters, prefer separate state.
Importing existing infrastructure
Section titled “Importing existing infrastructure”Bring click-ops resources under management with terraform import (or import blocks in
modern Terraform), and refactor safely with terraform state mv. Expect friction —
import populates state but not config, so you still write the matching HCL.
Drift detection
Section titled “Drift detection”Drift is when reality diverges from state (someone changed a resource by hand).
terraform plan is drift detection — run it on a schedule (CI cron) and alert on any
non-empty plan so out-of-band changes surface before they cause an outage.
OpenTofu
Section titled “OpenTofu”After HashiCorp moved Terraform to the BSL license in 2023, the community forked it as
OpenTofu (Linux Foundation, MPL-licensed). It is a
drop-in-compatible alternative for teams that want an open-source license; tofu mirrors
the terraform CLI and reads the same configs.
Related
Section titled “Related”- Reverse Proxy with nginx — the kind of service Terraform provisions
- PostgreSQL Server Guide — stateful infra to manage carefully
- Disaster Recovery — IaC makes rebuilding from scratch repeatable
- Docker — containers as another declarative layer