Summary
Check out this step-by-step guide to deploying AWS EC2 instances using Terraform, including examples for single and multi-instance provisioning, multi-region support, and reusable modules.
Database administrators typically have to deploy and de-provision many Amazon Elastic Compute Cloud (AWS EC2) instances every year. Terraform, an infrastructure as code (IaC) tool developed by HashiCorp that allows users to define and provision infrastructure using a declarative configuration language, automates this process, but it’s not as easy as pushing a button or entering a single command.
In this blog, we explain the steps involved in creating an AWS Instance with Terraform.
How to Write an EC2 Instance with Terraform: An Example
Terraform files contain commands to perform deployments and automation against the AWS interface. In this example, the EC2 instance is created in one file named ec2_create.tf and a separate variable file named variables.tf stores the name of the Amazon image, the size of the instance, and the name of the virtual private cloud (VPC).
Step 1: Create the EC2 File
The first step is to define the provider, which is AWS in this example. Then, you define the EC2 configurations. Use the following code for the ec2_create.tf file:
text
terraform
required_providers {
aws = {
= "hashicorp/aws"
version = "~> 6.0" # Updated to the latest AWS provider version
}
}
resource "aws_instance" "example_server" {
= var.ami
instance_type = var.instance_type
= var.aws_region # New region attribute at resource level
network_interface {
network_interface_id = var.network_interface_id
device_index = 0
}
credit_specification {
cpu_credits = "unlimited"
}
# Enhanced security configuration
metadata_options {
http_tokens = "required" # IMDSv2 enforcement
http_endpoint = "enabled
http_put_response_hop_limit = 1
root_block_device {
encrypted = true # Enable EBS encryption for security
volume_size = 20
}
tags = {
Name = "ExampleServer"
Environment = var.environment
ManagedBy = "Terraform"
}
}
In the commands above, an AWS instance is created with unlimited CPU usage. The resource name and VPC are set to variables created in the next step. The code now includes enhanced security features and leverages the new region attribute from AWS Provider 6.0.
Step 2: Create the Variables File
The ec2_create.tf file is a base template for creating an EC2 instance, but having a separate variable file makes it dynamic. Using a separate variable file lets you use the same base creation template for numerous other EC2 instances. Use the following code for the variables.tf file:
text
variable "network_interface_id" {
= string
= "network_id_from_aws"
description = "The ID of the network interface to attach to the instance"
}
variable "ami" {
type = string
default = "ami-04e914639d0cca79a" # Updated to a more current Amazon Linux AMI
description = "The AMI ID to use for the instance"
}
variable "instance_type" {
type = string
default = "t3.micro" # Updated to newer generation instance
description = "The type of instance to start"
}
variable "aws_region" {
= strin
= "us-east-1"
description = "The AWS region to deploy resources into
}
variable "environment" {
type = string
default = "development"
description = "The deployment environment (development, staging, production)"
}
The above code sets the instance type to the newer t3.micro and assigns the EC2 instance to a more recent Amazon Linux image. It also includes new variables for region and environment to support multi-region deployments.
Step 3: Execute Terraform Commands
With the files created, you can now send them to Terraform and execute the commands. First, you must initialize Terraform by using:
bash terraform init
You can validate the commands and ensure you have no errors in syntax using:
bash terraform plan
Next, apply the changes to your AWS environment:
bash terraform apply --auto-approve
For production environments, it’s recommended to use remote state storage for better collaboration and state management:
bash
# First, configure a backend in your configuration
terraform {
backend "s3" {
bucket = "terraform-state-bucket"
key = "ec2/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-locks"
}
}
How to Launch Multiple EC2 Instances in Terraform
In an enterprise environment, you might need several instances created at the same time to host multiple applications, test multiple versions of an application, or use as a group of hosts to perform a specific action. Modern Terraform practices offer more flexible approaches than simple count parameters.
Step 1: Create the EC2 File with Modern Approaches
Here’s a more sophisticated approach using a map of objects to define multiple instances with different configurations:
text
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
locals {
instances = {
"web-server-1" = {
instance_type = "c8g.large" # New compute-optimized ARM instance
region = "us-east-1"
ami = "ami-04e914639d0cca79a"
},
"db-server-1" = {
instance_type = "r7g.large" # New memory-optimized ARM instance
region = "us-east-1"
ami = "ami-04e914639d0cca79a"
},
"ai-workload-1" = {
instance_type = "p6g.4xlarge" # New GPU instance for AI/ML
region = "us-west-2" # Different region
ami = "ami-0b9f27b05e1de14e9"
}
}
}
resource "aws_instance" "multiple_servers" {
for_each = local.instances
ami = each.value.ami
instance_type = each.value.instance_type
region = each.value.region # Using region attribute for multi-region support
network_interface {
network_interface_id = var.network_interface_id
device_index = 0
}
credit_specification {
cpu_credits = "unlimited"
}
# Enhanced security configuration
metadata_options {
http_tokens
= "required" # IMDSv2 enforcement
http_endpoint = "enabled"
http_put_response_hop_limit = 1
}
root_block_device {
encrypted = true
volume_size = 30
}
tags = {
Name = each.key
Environment = var.environment
ManagedBy = "Terraform"
}
}
This approach allows you to define different instance configurations for various workloads, including the new 2025 EC2 instance types like C8, R7, and P6 series optimized for specific workloads.
Step 2: Create the Variables File
The variables file needs to be updated to support the multi-instance, multi-region approach:
text
variable "network_interface_id" {
= string
= "network_id_from_aws"
description = "The ID of the network interface to attach to the instance"
}
variable "environment" {
type = string
default = "development"
description = "The deployment environment (development, staging, production)"
}
Step 3: Execute the Terraform Commands with State Management
For multi-region deployments and team environments, proper state management is crucial:
bash # Initialize with remote backend terraform init # Create a workspace for each region terraform workspace new us-east-1 terraform workspace new us-west-2 # Select a workspace and plan terraform workspace select us-east-1 terraform plan # Apply changes terraform apply --auto-approve
When managing infrastructure across multiple regions, using Terraform workspaces can help isolate state files while keeping configurations flexible.
Using Terraform Modules for EC2 Deployment
For more reusable infrastructure, consider creating a custom EC2 module:
text
# modules/ec2_instance/main.tf
resource "aws_instance" "this" {
ami = var.ami
instance_type = var.instance_type
region = var.region
subnet_id = var.subnet_id
availability_zone = var.availability_zone
# Security groups
vpc_security_group_ids = var.security_group_ids
# Root volume
root_block_device
volume_type = var.root_volume_type
volume_size = var.root_volume_size
encrypted = true
}
tags = merge(
{
"Name" = var.name
},
var.tags
)
}
This module can then be called from your main configuration:
text
module "web_server"
source = "./modules/ec2_instance"
name = "web-server"
ami = "ami-04e914639d0cca79a"
instance_type = "c8g.large"
region = "us-east-1"
root_volume_size = 30
root_volume_type = "gp3"
tags = {
Environment = "production"
Application = "web"
}
}
Conclusion
Terraform makes it easy for administrators to provision cloud resources in AWS. Using Terraform’s command files, you can automate provisioning to reduce the overhead of manually creating instances in the AWS dashboard.
The AWS Provider 6.0 now supports multi-region deployments within a single configuration file through an injected region attribute at the resource level. This eliminates the need for multiple provider configurations, simplifies management, and reduces memory usage.
When designing your Terraform configurations, consider:
- Using remote state storage with state locking for team environments
- Leveraging the latest EC2 instance types like C8, R7, and P6 series for optimized workloads
- Implementing proper security controls including encryption and IMDSv2 enforcement
- Creating reusable modules for consistent infrastructure deployment
- Using Terraform workspaces for managing multi-region deployments
By following these modern practices, you can create scalable, secure, and efficient infrastructure as code for your AWS environment.






