Terraform Tutorial — Project 2: EC2 Web Server
Create an EC2 instance running a web server with a security group that allows HTTP and SSH traffic.
What You’ll Build
- EC2 instance with Amazon Linux 2023
- Security group allowing ports 22 (SSH) and 80 (HTTP)
- User data script that installs and starts nginx
- Outputs for the public IP and SSH command
Project Structure
project-2-ec2-webserver/
├── main.tf
├── variables.tf
└── outputs.tf
variables.tf
variable "region" {
type = string
default = "us-east-1"
}
variable "instance_type" {
type = string
default = "t3.micro"
}
variable "key_name" {
type = string
description = "Name of the SSH key pair"
}
main.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.region
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
resource "aws_security_group" "web" {
name = "web-server-sg"
description = "Allow HTTP and SSH"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow HTTP"
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow SSH"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound"
}
tags = {
Name = "web-server-sg"
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
key_name = var.key_name
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y nginx
systemctl start nginx
systemctl enable nginx
echo "<h1>Hello from Terraform!</h1><p>Instance: $(hostname)</p>" > /usr/share/nginx/html/index.html
EOF
tags = {
Name = "terraform-web-server"
}
}
outputs.tf
output "public_ip" {
value = aws_instance.web.public_ip
description = "Public IP of the web server"
}
output "web_url" {
value = "http://${aws_instance.web.public_ip}"
description = "URL to access the web server"
}
output "ssh_command" {
value = "ssh -i ${var.key_name}.pem ec2-user@${aws_instance.web.public_ip}"
description = "SSH command to connect"
}
Deploy
$ terraform init
$ terraform apply -var="key_name=my-key-pair"
# Test the web server
$ curl $(terraform output -raw web_url)
# Clean up
$ terraform destroy -var="key_name=my-key-pair"