DEV Community

Alex Spinov
Alex Spinov

Posted on

Terraform Has a Free API — Infrastructure as Code for Any Cloud

Terraform is the industry-standard Infrastructure as Code tool by HashiCorp — define your entire cloud infrastructure in declarative config files, version it in Git, and deploy with one command.

Why Terraform?

  • Multi-cloud — AWS, GCP, Azure, DigitalOcean, Cloudflare, 3000+ providers
  • Declarative — describe the desired state, Terraform figures out how to get there
  • Plan before apply — preview changes before executing them
  • State management — tracks what exists vs what you want
  • Modules — reusable infrastructure components
  • Free and open source — OpenTofu fork also available

Quick Start

# Install
brew install terraform
# or
curl -fsSL https://releases.hashicorp.com/terraform/1.9.0/terraform_1.9.0_linux_amd64.zip -o tf.zip && unzip tf.zip

terraform --version
Enter fullscreen mode Exit fullscreen mode

Your First Infrastructure

# main.tf — Deploy a web server on AWS

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

# VPC
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = { Name = "my-vpc" }
}

# Subnet
resource "aws_subnet" "public" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-east-1a"
  map_public_ip_on_launch = true
}

# Security group
resource "aws_security_group" "web" {
  vpc_id = aws_vpc.main.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# EC2 instance
resource "aws_instance" "web" {
  ami           = "ami-0c02fb55956c7d316"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.web.id]

  user_data = <<-EOF
    #!/bin/bash
    yum update -y
    yum install -y httpd
    systemctl start httpd
    echo "Hello from Terraform!" > /var/www/html/index.html
  EOF

  tags = { Name = "web-server" }
}

output "public_ip" {
  value = aws_instance.web.public_ip
}
Enter fullscreen mode Exit fullscreen mode
terraform init    # Download providers
terraform plan    # Preview changes
terraform apply   # Create infrastructure
terraform destroy # Tear everything down
Enter fullscreen mode Exit fullscreen mode

Variables and Outputs

# variables.tf
variable "environment" {
  type    = string
  default = "staging"
  validation {
    condition     = contains(["dev", "staging", "production"], var.environment)
    error_message = "Must be dev, staging, or production."
  }
}

variable "instance_count" {
  type    = number
  default = 2
}

variable "allowed_ips" {
  type    = list(string)
  default = ["0.0.0.0/0"]
}

# terraform.tfvars
environment    = "production"
instance_count = 3
allowed_ips    = ["203.0.113.0/24", "198.51.100.0/24"]
Enter fullscreen mode Exit fullscreen mode

Modules (Reusable Infrastructure)

# modules/web-app/main.tf
variable "name" { type = string }
variable "instance_type" { default = "t3.micro" }
variable "min_size" { default = 1 }
variable "max_size" { default = 3 }

resource "aws_launch_template" "app" {
  name_prefix   = var.name
  image_id      = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type
}

resource "aws_autoscaling_group" "app" {
  name                = "${var.name}-asg"
  min_size            = var.min_size
  max_size            = var.max_size
  launch_template {
    id      = aws_launch_template.app.id
    version = "$Latest"
  }
}

# Usage
module "api" {
  source        = "./modules/web-app"
  name          = "api"
  instance_type = "t3.small"
  min_size      = 2
  max_size      = 10
}

module "worker" {
  source        = "./modules/web-app"
  name          = "worker"
  instance_type = "t3.medium"
  min_size      = 1
  max_size      = 5
}
Enter fullscreen mode Exit fullscreen mode

Remote State (Team Collaboration)

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}
Enter fullscreen mode Exit fullscreen mode

Terraform vs Pulumi vs CloudFormation vs CDK

Feature Terraform Pulumi CloudFormation CDK
Language HCL Any (TS, Python, Go) YAML/JSON TypeScript
Multi-cloud Yes (3000+ providers) Yes AWS only AWS only
State Self-managed/Cloud Pulumi Cloud AWS-managed AWS-managed
Plan terraform plan pulumi preview Change sets cdk diff
Community Largest Growing AWS only AWS only
Learning HCL (easy) Your language YAML (verbose) TypeScript
Cost Free (OSS) Free tier Free Free

Need to scrape data from any website and get it in structured JSON? Check out my web scraping tools on Apify — no coding required, results in minutes.

Have a custom data extraction project? Email me at spinov001@gmail.com — I build tailored scraping solutions for businesses.

Top comments (0)