Creating Your First AWS EC2 Instance with Terraform
A step-by-step guide to launching and managing EC2 instances using Infrastructure as Code with Terraform
Creating Your First AWS EC2 Instance with Terraform
Amazon EC2 (Elastic Compute Cloud) is one of the most fundamental services in AWS. In this guide, we’ll walk through creating and managing EC2 instances using Terraform, making your infrastructure deployment reproducible and version-controlled.
Video Tutorial
Learn more about managing AWS EC2 with Terraform in this comprehensive video tutorial:
Prerequisites
- AWS CLI installed and configured with appropriate credentials
- Terraform installed (version 1.0.0 or later)
- Basic understanding of AWS EC2 concepts
- Text editor of your choice
Project Structure
ec2-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars
Setting Up the Provider
Create main.tf
:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
region = var.aws_region
}
# VPC for our EC2 instance
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
}
}
# Public subnet
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = var.subnet_cidr
availability_zone = "${var.aws_region}a"
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-subnet"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-igw"
}
}
# Route table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.project_name}-public-rt"
}
}
# Route table association
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# Security group
resource "aws_security_group" "ec2" {
name = "${var.project_name}-ec2-sg"
description = "Security group for EC2 instance"
vpc_id = aws_vpc.main.id
ingress {
description = "SSH from anywhere"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP from anywhere"
from_port = 80
to_port = 80
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"]
}
tags = {
Name = "${var.project_name}-ec2-sg"
}
}
# EC2 instance
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.ec2.id]
key_name = var.key_name
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Terraform-managed EC2!</h1>" > /var/www/html/index.html
EOF
tags = {
Name = "${var.project_name}-web"
}
}
Variables Configuration
Create variables.tf
:
variable "aws_region" {
description = "AWS region"
type = string
default = "us-west-2"
}
variable "project_name" {
description = "Name of the project"
type = string
default = "terraform-ec2-demo"
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
variable "subnet_cidr" {
description = "CIDR block for subnet"
type = string
default = "10.0.1.0/24"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t2.micro"
}
variable "ami_id" {
description = "AMI ID for EC2 instance"
type = string
# Amazon Linux 2 AMI ID for us-west-2
default = "ami-0735c191cf914754d"
}
variable "key_name" {
description = "Name of the SSH key pair"
type = string
}
Output Configuration
Create outputs.tf
:
output "instance_public_ip" {
description = "Public IP of the EC2 instance"
value = aws_instance.web.public_ip
}
output "instance_public_dns" {
description = "Public DNS of the EC2 instance"
value = aws_instance.web.public_dns
}
Deployment Steps
- Initialize Terraform:
terraform init
-
Create a key pair in AWS and note its name.
-
Create
terraform.tfvars
:
aws_region = "us-west-2"
project_name = "my-ec2-demo"
key_name = "your-key-pair-name"
- Review the plan:
terraform plan
- Apply the configuration:
terraform apply
Accessing Your EC2 Instance
After deployment, you can:
- SSH into your instance:
ssh -i path/to/your-key.pem ec2-user@$(terraform output -raw instance_public_ip)
- View the web page by visiting the public IP in your browser:
echo "http://$(terraform output -raw instance_public_ip)"
Best Practices
-
Security:
- Restrict security group rules to specific IP ranges
- Use SSH key pairs instead of passwords
- Regularly update AMIs for security patches
-
Cost Management:
- Use appropriate instance types for your needs
- Implement auto-shutdown for non-production instances
- Tag resources for cost allocation
-
Maintenance:
- Use data sources for AMI IDs to get the latest versions
- Implement backup strategies
- Monitor instance metrics
Cleanup
To avoid ongoing charges, destroy the resources when not needed:
terraform destroy
Common Issues and Solutions
-
Connection Timeout:
- Check security group rules
- Verify subnet routing
- Confirm key pair permissions
-
Instance Launch Failure:
- Verify AMI ID is valid for the region
- Check instance type availability
- Confirm sufficient AWS limits
-
User Data Script Issues:
- Check instance logs in AWS Console
- Verify script syntax
- Ensure proper permissions
Next Steps
Consider exploring:
- Auto Scaling Groups
- Load Balancers
- Custom AMIs
- Instance Profiles
- CloudWatch monitoring
Conclusion
You’ve successfully created an EC2 instance using Terraform! This Infrastructure as Code approach makes it easy to version control your infrastructure and maintain consistency across deployments.
Remember to:
- Follow security best practices
- Monitor costs
- Keep your Terraform configurations up to date
- Document any customizations