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.
Prerequisites
You should have:
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)
Directory Structure
Here’s the Terraform project layout we will use:
.
├── instance.tf
├── key_pair.tf
├── output.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf
Each file handles a specific part of the deployment.
Provider Configuration
Start with the provider definition in provider.tf:
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
}
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.
Defining Variables
In variables.tf, define the parameters Terraform will use.
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
}
These variables make the configuration reusable. For example, you can switch AWS regions or key names without touching the main code.
Creating an SSH Key Pair
key_pair.tf handles SSH key generation and registration with AWS.
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
}
- The TLS provider generates a 4096-bit RSA key.
- The local_file resource writes the private key locally as a
.pemfile. - The aws_key_pair resource uploads the public key to AWS.
Once deployed, you’ll use the .pem file for SSH access to your EC2 instance.
Defining the EC2 Instance
instance.tf defines both the EC2 instance and the security group.
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"
}
}
What happens here
- 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
By the time Terraform finishes, Nginx is already serving traffic.
Security Group
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"]
}
}
It allows:
- SSH (22) for remote access
- HTTP (80) and HTTPS (443) for web traffic
- All outbound traffic for updates and package installations
Outputting Useful Information
In output.tf, display key connection details after provisioning:
output "aws_instance_public_ip" {
value = aws_instance.web-server.public_ip
}
output "aws_instance_public_dns" {
value = aws_instance.web-server.public_dns
}
After terraform apply, you’ll see the public IP and DNS name printed on your terminal.
Deploying the Infrastructure
Create a terraform.tfvars file to provide variable values:
region = "eu-north-1"
access_key = "YOUR_ACCESS_KEY"
secret_key = "YOUR_SECRET_KEY"
file_name = "demo-key.pem"
You can also use environment variables to assign values for access_key and secret_key.
export TF_VAR_access_key="YOUR_ACCESS_KEY"
export TF_VAR_secret_key="YOUR_SECRET_KEY"
Once all files are in place, run:
terraform init
terraform plan
terraform apply
Terraform will:
- Generate a key pair
- Create a security group
- Launch the EC2 instance
- Run the Nginx installation script
- Print the public IP and DNS
Open the public IP in your browser.
You should see the Nginx welcome page — that confirms a successful automated deployment.
Verifying from the Instance
You can SSH in if you want to verify Nginx status:
chmod 400 demo-key.pem
ssh -i demo-key.pem ubuntu@<public_ip>
sudo systemctl status nginx
Cleaning Up
When you’re done testing:
terraform destroy
This removes the instance, key pair, and security group.
Terraform tracks all managed resources, so cleanup is safe and predictable.
Conclusion
We've automatically deployed a secure, Nginx-powered EC2 instance using Terraform.
Top comments (0)