How to Provision an AWS EC2 Instance with Terraform
An EC2 instance in Terraform is the aws_instance resource - it just needs a real AMI id and a valid instance type. The two things that break apply are a placeholder AMI and a bad instance-type name. Here's how to get both right.
The resource
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890" # a REAL ami id for your region
instance_type = "t3.micro" # a valid type
tags = { Name = "web" }
}
Two fields do all the work - and both are where applies fail.
Don't hard-code a placeholder AMI
AMI ids are region-specific and change over time, so ami-deadbeef or a copied id
from a tutorial will fail. Look up a current one with a data source instead of pasting:
data "aws_ami" "al2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.al2023.id # always a valid, current id
instance_type = "t3.micro"
}
Use a valid instance type
Instance types follow family + size: t3.micro, t3.small, m5.large. A bad suffix
like t2.nano-x isn't a real type and errors on apply. When unsure, t3.micro is a safe,
cheap default.
Apply
terraform init
terraform plan # see exactly what will be created
terraform apply -auto-approve
How to debug
- The error names the field - "InvalidAMIID" (bad/placeholder AMI) or an invalid instance-type message.
- Use the
aws_amidata source so the AMI is never stale. terraform planfirst - confirm the resolved AMI + type before creating anything.
Look up the AMI instead of hard-coding it
A hard-coded AMI id rots: it is region-specific and gets deprecated. Resolve the latest one at plan time with a data source:
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
}
Then reference ami = data.aws_ami.ubuntu.id. Beyond the AMI and instance type, a usable instance needs key_name for SSH access, vpc_security_group_ids to control traffic, subnet_id to place it, and tags so you can find and bill it. Use user_data to run a bootstrap script on first boot. Together these turn a bare instance into one you can actually reach and manage.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Looking up a current AMI with the aws_ami data source
- Choosing a valid instance_type
- Using terraform plan to verify before apply
FAQ
How do I create an EC2 instance with Terraform?
Use the aws_instance resource with a valid ami and instance_type, then terraform init and terraform apply. Look the AMI up with an aws_ami data source rather than hard-coding it.
Why does Terraform say InvalidAMIID?
The AMI id is a placeholder or from another region - AMI ids are region-specific. Use an aws_ami data source (most_recent + a name filter) so Terraform resolves a current, valid id automatically.
What's a valid EC2 instance_type?
family.size, e.g. t3.micro, t3.small, m5.large. Invalid suffixes like t2.nano-x fail on apply. t3.micro is a safe cheap default.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →