VPC
├── Private Subnet (10.0.1.0/24)
├── Public Subnet (10.0.2.0/24)
│ └── EC2 (Nginx installed via user_data)
├── Internet Gateway
├── Route Table → Public Subnet → IGW
└── Security Group → Allow HTTP port 80
Output: http://<public-ip> → Nginx webpage in browser
aws-vpc-ec2-nginx/
├── main.tf # Provider config
├── vpc.tf # VPC, subnets, IGW, route table
├── ec2.tf # EC2 instance
├── security_groups.tf # Security group rules
└── outputs.tf # Website URL output
One file works too but separate files = easier to manage
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.32.1"
}
}
}
provider "aws" {
region = "eu-north-1"
}
# VPC - main private network
resource "aws_vpc" "my_vpc" {
cidr_block = "10.0.0.0/16"
tags = { Name = "my_vpc" }
}
# Private Subnet - no internet (for DB, backend)
resource "aws_subnet" "private-subnet" {
cidr_block = "10.0.1.0/24"
vpc_id = aws_vpc.my_vpc.id
tags = { Name = "private-subnet" }
}
# Public Subnet - has internet access
# map_public_ip_on_launch = true → auto assign public IP to instances
resource "aws_subnet" "public-subnet" {
cidr_block = "10.0.2.0/24"
vpc_id = aws_vpc.my_vpc.id
map_public_ip_on_launch = true # Every instance here gets public IP
tags = { Name = "public-subnet" }
}
# Internet Gateway - connects VPC to internet
resource "aws_internet_gateway" "my-igw" {
vpc_id = aws_vpc.my_vpc.id
tags = { Name = "my-igw" }
}
# Route Table - send all traffic to IGW
resource "aws_route_table" "my-rt" {
vpc_id = aws_vpc.my_vpc.id
route {
cidr_block = "0.0.0.0/0" # All traffic
gateway_id = aws_internet_gateway.my-igw.id # Go through IGW
}
}
# Associate public subnet with route table
resource "aws_route_table_association" "public-sub" {
route_table_id = aws_route_table.my-rt.id
subnet_id = aws_subnet.public-subnet.id
}
resource "aws_security_group" "nginx-sg" {
vpc_id = aws_vpc.my_vpc.id
# Inbound - Allow HTTP (port 80) from anywhere
# Without this → server runs but no one can access it from browser
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Anyone can access
}
# Outbound - Allow all traffic out
# Needed for yum install to download packages
egress {
from_port = 0
to_port = 0
protocol = "-1" # -1 = all protocols
cidr_blocks = ["0.0.0.0/0"]
}
tags = { Name = "nginx-sg" }
}
Ingress = Inbound = Traffic coming IN (HTTP request from browser)
Egress = Outbound = Traffic going OUT (downloading nginx package)