Tools
Tools: Part-4: Automating EC2 Infrastructure using Terraform | Amazon Web Services (AWS)
2026-02-19
0 views
admin
Prerequisites ## Directory Structure ## Provider Configuration ## Defining Variables ## Creating an SSH Key Pair ## Defining the EC2 Instance ## What happens here ## Security Group ## Outputting Useful Information ## Deploying the Infrastructure ## Verifying from the Instance ## Cleaning Up ## Conclusion Earlier, we created an EC2 instance by hand in the AWS Console. Now we’ll do the same thing with Terraform. In this guide, we will walk through how to use Terraform to create an EC2 instance on AWS, generate an SSH key, and install Nginx when the server boots. All of it is automated using code. Terraform installed on your machine An IAM user with an access key and secret key A general idea of how EC2 works A basic understanding of Terraform (providers, resources, variables, outputs) Here’s the Terraform project layout we will use: Each file handles a specific part of the deployment. Start with the provider definition in provider.tf: This tells Terraform to use the AWS provider and defines how to authenticate.
In practice, you should avoid storing credentials in code or tfvars files — use the AWS CLI (aws configure) or environment variables for safer authentication. In variables.tf, define the parameters Terraform will use. These variables make the configuration reusable. For example, you can switch AWS regions or key names without touching the main code. key_pair.tf handles SSH key generation and registration with AWS. Once deployed, you’ll use the .pem file for SSH access to your EC2 instance. instance.tf defines both the EC2 instance and the security group. A user_data script runs automatically on boot: By the time Terraform finishes, Nginx is already serving traffic. In output.tf, display key connection details after provisioning: After terraform apply, you’ll see the public IP and DNS name printed on your terminal. Create a terraform.tfvars file to provide variable values: You can also use environment variables to assign values for access_key and secret_key. Once all files are in place, run: Open the public IP in your browser.
You should see the Nginx welcome page — that confirms a successful automated deployment. You can SSH in if you want to verify Nginx status: When you’re done testing: This removes the instance, key pair, and security group.
Terraform tracks all managed resources, so cleanup is safe and predictable. We've automatically deployed a secure, Nginx-powered EC2 instance using Terraform. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
.
├── instance.tf
├── key_pair.tf
├── output.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
.
├── instance.tf
├── key_pair.tf
├── output.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf CODE_BLOCK:
.
├── instance.tf
├── key_pair.tf
├── output.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf CODE_BLOCK:
terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.15.0" } }
} provider "aws" { region = var.region access_key = var.access_key secret_key = var.secret_key
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.15.0" } }
} provider "aws" { region = var.region access_key = var.access_key secret_key = var.secret_key
} CODE_BLOCK:
terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.15.0" } }
} provider "aws" { region = var.region access_key = var.access_key secret_key = var.secret_key
} CODE_BLOCK:
variable "access_key" { type = string
} variable "secret_key" { type = string
} variable "region" { type = string default = "eu-north-1"
} variable "file_name" { description = "Local file name for private key" type = string
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
variable "access_key" { type = string
} variable "secret_key" { type = string
} variable "region" { type = string default = "eu-north-1"
} variable "file_name" { description = "Local file name for private key" type = string
} CODE_BLOCK:
variable "access_key" { type = string
} variable "secret_key" { type = string
} variable "region" { type = string default = "eu-north-1"
} variable "file_name" { description = "Local file name for private key" type = string
} CODE_BLOCK:
resource "tls_private_key" "rsa-4096-key" { algorithm = "RSA" rsa_bits = 4096
} resource "local_file" "tf_key" { content = tls_private_key.rsa-4096-key.private_key_pem filename = var.file_name
} resource "aws_key_pair" "demo-key-pair-tf" { key_name = "demo-key-pair-tf" public_key = tls_private_key.rsa-4096-key.public_key_openssh
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
resource "tls_private_key" "rsa-4096-key" { algorithm = "RSA" rsa_bits = 4096
} resource "local_file" "tf_key" { content = tls_private_key.rsa-4096-key.private_key_pem filename = var.file_name
} resource "aws_key_pair" "demo-key-pair-tf" { key_name = "demo-key-pair-tf" public_key = tls_private_key.rsa-4096-key.public_key_openssh
} CODE_BLOCK:
resource "tls_private_key" "rsa-4096-key" { algorithm = "RSA" rsa_bits = 4096
} resource "local_file" "tf_key" { content = tls_private_key.rsa-4096-key.private_key_pem filename = var.file_name
} resource "aws_key_pair" "demo-key-pair-tf" { key_name = "demo-key-pair-tf" public_key = tls_private_key.rsa-4096-key.public_key_openssh
} CODE_BLOCK:
resource "aws_instance" "web-server" { ami = "ami-0a716d3f3b16d290c" instance_type = "t3.micro" key_name = aws_key_pair.demo-key-pair-tf.key_name security_groups = [aws_security_group.demo-sg.name] user_data = <<-EOF #!/bin/bash apt update -y apt install nginx -y systemctl enable nginx systemctl start nginx
EOF tags = { Name = "web-server" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
resource "aws_instance" "web-server" { ami = "ami-0a716d3f3b16d290c" instance_type = "t3.micro" key_name = aws_key_pair.demo-key-pair-tf.key_name security_groups = [aws_security_group.demo-sg.name] user_data = <<-EOF #!/bin/bash apt update -y apt install nginx -y systemctl enable nginx systemctl start nginx
EOF tags = { Name = "web-server" }
} CODE_BLOCK:
resource "aws_instance" "web-server" { ami = "ami-0a716d3f3b16d290c" instance_type = "t3.micro" key_name = aws_key_pair.demo-key-pair-tf.key_name security_groups = [aws_security_group.demo-sg.name] user_data = <<-EOF #!/bin/bash apt update -y apt install nginx -y systemctl enable nginx systemctl start nginx
EOF tags = { Name = "web-server" }
} CODE_BLOCK:
resource "aws_security_group" "demo-sg" { name = "demo-sg" ingress { description = "SSH access" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTP access" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTPS access" 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"] }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
resource "aws_security_group" "demo-sg" { name = "demo-sg" ingress { description = "SSH access" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTP access" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTPS access" 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"] }
} CODE_BLOCK:
resource "aws_security_group" "demo-sg" { name = "demo-sg" ingress { description = "SSH access" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTP access" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "HTTPS access" 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"] }
} CODE_BLOCK:
output "aws_instance_public_ip" { value = aws_instance.web-server.public_ip
} output "aws_instance_public_dns" { value = aws_instance.web-server.public_dns
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
output "aws_instance_public_ip" { value = aws_instance.web-server.public_ip
} output "aws_instance_public_dns" { value = aws_instance.web-server.public_dns
} CODE_BLOCK:
output "aws_instance_public_ip" { value = aws_instance.web-server.public_ip
} output "aws_instance_public_dns" { value = aws_instance.web-server.public_dns
} CODE_BLOCK:
region = "eu-north-1" access_key = "YOUR_ACCESS_KEY"
secret_key = "YOUR_SECRET_KEY"
file_name = "demo-key.pem" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
region = "eu-north-1" access_key = "YOUR_ACCESS_KEY"
secret_key = "YOUR_SECRET_KEY"
file_name = "demo-key.pem" CODE_BLOCK:
region = "eu-north-1" access_key = "YOUR_ACCESS_KEY"
secret_key = "YOUR_SECRET_KEY"
file_name = "demo-key.pem" CODE_BLOCK:
export TF_VAR_access_key="YOUR_ACCESS_KEY"
export TF_VAR_secret_key="YOUR_SECRET_KEY" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
export TF_VAR_access_key="YOUR_ACCESS_KEY"
export TF_VAR_secret_key="YOUR_SECRET_KEY" CODE_BLOCK:
export TF_VAR_access_key="YOUR_ACCESS_KEY"
export TF_VAR_secret_key="YOUR_SECRET_KEY" CODE_BLOCK:
terraform init
terraform plan
terraform apply Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
terraform init
terraform plan
terraform apply CODE_BLOCK:
terraform init
terraform plan
terraform apply CODE_BLOCK:
chmod 400 demo-key.pem
ssh -i demo-key.pem ubuntu@<public_ip>
sudo systemctl status nginx Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
chmod 400 demo-key.pem
ssh -i demo-key.pem ubuntu@<public_ip>
sudo systemctl status nginx CODE_BLOCK:
chmod 400 demo-key.pem
ssh -i demo-key.pem ubuntu@<public_ip>
sudo systemctl status nginx CODE_BLOCK:
terraform destroy Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
terraform destroy CODE_BLOCK:
terraform destroy - An AWS account
- Terraform installed on your machine
- An IAM user with an access key and secret key
- A general idea of how EC2 works
- A basic understanding of Terraform (providers, resources, variables, outputs) - The TLS provider generates a 4096-bit RSA key.
- The local_file resource writes the private key locally as a .pem file.
- The aws_key_pair resource uploads the public key to AWS. - Terraform launches an Ubuntu 24.04 EC2 instance using the AMI ID above.
- A user_data script runs automatically on boot: Updates packages
Installs and starts Nginx
Enables it to start on boot
- Updates packages
- Installs and starts Nginx
- Enables it to start on boot
- By the time Terraform finishes, Nginx is already serving traffic. - Updates packages
- Installs and starts Nginx
- Enables it to start on boot - SSH (22) for remote access
- HTTP (80) and HTTPS (443) for web traffic
- All outbound traffic for updates and package installations - Generate a key pair
- Create a security group
- Launch the EC2 instance
- Run the Nginx installation script
- Print the public IP and DNS
how-totutorialguidedev.toaiubuntuserverbashdnsswitchnginxterraform