Terraform Demos
Copy and modify these pre-built Terraform configurations for your infrastructure.
AWSAWS EC2 Instance with Security Group
●AWSUploadedLaunch an EC2 instance with a properly scoped security group and user data.
By System · Compute
▾
AWS EC2 Instance with Security Group
●AWSUploadedLaunch an EC2 instance with a properly scoped security group and user data.
By System · Compute
main.tf · variables.tf · outputs.tf
Downloadterraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
}
resource "aws_security_group" "app" {
name = "${var.app_name}-sg"
description = "Allow SSH and app traffic"
vpc_id = var.vpc_id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.ssh_cidr]
}
ingress {
from_port = var.app_port
to_port = var.app_port
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"]
}
}
resource "aws_instance" "app" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = var.subnet_id
vpc_security_group_ids = [aws_security_group.app.id]
user_data = <<-EOF
#!/bin/bash
apt-get update -y
apt-get install -y docker.io
systemctl enable docker
systemctl start docker
EOF
tags = { Name = var.app_name }
}
variable "aws_region" {
type = string
default = "us-east-1"
}
variable "app_name" {
type = string
}
variable "instance_type" {
type = string
default = "t3.micro"
}
variable "app_port" {
type = number
default = 3000
}
variable "ssh_cidr" {
type = string
default = "0.0.0.0/0"
}
variable "vpc_id" {
type = string
}
variable "subnet_id" {
type = string
}Troubleshooting & Solutions
Common Issues
- Instance unreachable via SSH
- AMI not found in region
- Security group too permissive
Solutions
- Scope ssh_cidr to your own IP, not 0.0.0.0/0, in real deployments
- AMI IDs are region-specific — use the data source, not a hardcoded ID
- Restrict ingress rules to only the ports actually needed
Troubleshooting Steps
- Confirm the subnet has a route to an internet gateway if public access is needed
- Check the security group allows your actual source IP
- Verify the instance has a public IP if you're connecting externally
- Check user_data logs at /var/log/cloud-init-output.log on the instance
Version compatibility: Terraform >= 1.0, AWS Provider >= 5.0
AWSAWS Auto Scaling Group with Launch Template
●AWSUploadedCreate an ASG with a launch template and target-tracking scaling policy.
By System · Compute
▾
AWS Auto Scaling Group with Launch Template
●AWSUploadedCreate an ASG with a launch template and target-tracking scaling policy.
By System · Compute
main.tf · variables.tf · outputs.tf
Downloadresource "aws_launch_template" "app" {
name_prefix = "${var.app_name}-"
image_id = var.ami_id
instance_type = var.instance_type
network_interfaces {
security_groups = [var.security_group_id]
}
tag_specifications {
resource_type = "instance"
tags = { Name = var.app_name }
}
}
resource "aws_autoscaling_group" "app" {
name = "${var.app_name}-asg"
desired_capacity = var.desired_capacity
min_size = var.min_size
max_size = var.max_size
vpc_zone_identifier = var.subnet_ids
target_group_arns = var.target_group_arns
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
}
resource "aws_autoscaling_policy" "cpu" {
name = "${var.app_name}-cpu-scaling"
autoscaling_group_name = aws_autoscaling_group.app.name
policy_type = "TargetTrackingScaling"
target_tracking_configuration {
predefined_metric_specification {
predefined_metric_type = "ASGAverageCPUUtilization"
}
target_value = 60
}
}
variable "app_name" {
type = string
}
variable "ami_id" {
type = string
}
variable "instance_type" {
type = string
default = "t3.micro"
}
variable "security_group_id" {
type = string
}
variable "subnet_ids" {
type = list(string)
}
variable "target_group_arns" {
type = list(string)
default = []
}
variable "desired_capacity" {
type = number
default = 2
}
variable "min_size" {
type = number
default = 1
}
variable "max_size" {
type = number
default = 4
}Troubleshooting & Solutions
Common Issues
- Instances launch then immediately terminate
- Scaling policy never triggers
- New launch template version not picked up
Solutions
- Check the launch template's AMI/instance type is valid in the target AZ
- Confirm CloudWatch metrics are actually being published for the ASG
- Reference "$Latest" (not a pinned version) if you want new instances to pick up template changes automatically
Troubleshooting Steps
- Check ASG activity history for the termination reason
- Verify the launch template's security group and subnet are compatible
- Confirm target tracking has enough data points before expecting it to scale
- Check IAM permissions for the ASG service-linked role
Version compatibility: Terraform >= 1.0, AWS Provider >= 5.0
AzureAzure Virtual Machine with Extensions
●AzureUploadedCreate an Azure VM with a custom script extension and a managed disk.
By System · Compute
▾
Azure Virtual Machine with Extensions
●AzureUploadedCreate an Azure VM with a custom script extension and a managed disk.
By System · Compute
main.tf · variables.tf · outputs.tf
Downloadresource "azurerm_network_interface" "main" {
name = "${var.app_name}-nic"
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "internal"
subnet_id = var.subnet_id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "main" {
name = var.app_name
resource_group_name = var.resource_group_name
location = var.location
size = var.vm_size
admin_username = var.admin_username
network_interface_ids = [azurerm_network_interface.main.id]
admin_ssh_key {
username = var.admin_username
public_key = var.ssh_public_key
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}
}
resource "azurerm_virtual_machine_extension" "docker" {
name = "install-docker"
virtual_machine_id = azurerm_linux_virtual_machine.main.id
publisher = "Microsoft.Azure.Extensions"
type = "CustomScript"
type_handler_version = "2.1"
settings = jsonencode({
commandToExecute = "apt-get update -y && apt-get install -y docker.io"
})
}
variable "app_name" {
type = string
}
variable "location" {
type = string
default = "East US"
}
variable "resource_group_name" {
type = string
}
variable "subnet_id" {
type = string
}
variable "vm_size" {
type = string
default = "Standard_B1s"
}
variable "admin_username" {
type = string
default = "azureuser"
}
variable "ssh_public_key" {
type = string
}Troubleshooting & Solutions
Common Issues
- SSH key format rejected
- Extension fails silently
- VM size unavailable in the region
Solutions
- admin_ssh_key expects the exact OpenSSH public key format (ssh-rsa/ssh-ed25519 ...)
- Check extension status with `az vm extension list` — failures log to /var/log/azure on the VM
- Pick a VM size actually available in your target region/zone via `az vm list-sizes`
Troubleshooting Steps
- Verify the SSH public key has no trailing newline issues
- Check the custom script extension's exit code and stdout/stderr logs
- Confirm the subnet has enough free IP addresses
- Check the subscription's quota for the requested VM size family
Version compatibility: Terraform >= 1.0, AzureRM Provider >= 3.0
GCPGoogle Compute Engine Instance
●GCPUploadedCreate a GCE instance with a startup script and proper tags.
By System · Compute
▾
Google Compute Engine Instance
●GCPUploadedCreate a GCE instance with a startup script and proper tags.
By System · Compute
main.tf · variables.tf · outputs.tf
Downloadresource "google_compute_instance" "app" {
name = var.app_name
machine_type = var.machine_type
zone = var.zone
tags = ["web", "ssh"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = 20
}
}
network_interface {
network = var.network_id
subnetwork = var.subnetwork_id
access_config {}
}
metadata_startup_script = <<-EOF
#!/bin/bash
apt-get update -y
apt-get install -y docker.io
systemctl enable docker
systemctl start docker
EOF
service_account {
scopes = ["cloud-platform"]
}
}
variable "app_name" {
type = string
}
variable "machine_type" {
type = string
default = "e2-small"
}
variable "zone" {
type = string
default = "us-central1-a"
}
variable "network_id" {
type = string
}
variable "subnetwork_id" {
type = string
}Troubleshooting & Solutions
Common Issues
- Startup script doesn't run
- No external IP assigned
- Instance stuck provisioning
Solutions
- Check startup script logs via `gcloud compute instances get-serial-port-output`
- An empty `access_config {}` block is what actually grants an ephemeral external IP — remove it for internal-only instances
- Verify the boot disk image family/project name is spelled exactly right
Troubleshooting Steps
- Check serial port output for boot and startup-script errors
- Confirm the service account has the scopes/IAM roles the startup script needs
- Verify zone matches an actual zone in the target region
- Check project quotas for CPUs/instances in that region
Version compatibility: Terraform >= 1.0, Google Provider >= 5.0