Flowchart
This flowchart outlines the process of deploying innnomax.space web application.
- Code & Repository: You will create a simple web application and push it to a GitHub repository.
- Terraform Configuration: You will write Terraform code to define your infrastructure.
- AWS & Terraform: Terraform will interact with the AWS API to provision resources.
- Provisioning: The following AWS resources will be created: o Amazon Linux EC2 Instance: This is where your web app will run. o Security Group: This acts as a virtual firewall, allowing web traffic (HTTP/HTTPS). o Elastic IP (EIP): This provides a static public IP address for your instance.
- DNS & Domain: The Elastic IP will be associated with your domain name, innomax.space, using your domain registrar's DNS settings. “Z.com”
- User Data Script: A user data script will be used to automatically install the necessary software on the EC2 instance, including Git and Nginx, and to clone your repository from GitHub.
- Web Application: Your web application will be accessible via your domain name.
Prerequisites
• AWS Account: You must have an AWS account with an Access Key and Secret Access Key.
• Terraform: Download and install Terraform on your local machine.
• Git: Download and install Git on your local machine.
• GitHub Account: Create a GitHub account.
• Domain Name: Your domain name, innomax.space, registered with a registrar like Z.COM.
Lab Steps
Step 1: Create a GitHub Repository & Web Page
- Log in to your GitHub account and create a new public repository named innomax-web-app. Do not initialize it with a README file.
- On your local machine, create a new folder and initialize it as a Git repository.
Bash
mkdir innomax-web-app
cd innomax-web-app
git init
- Create a simple HTML file named “index.html” inside the folder.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to Innomax!</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Inter', sans-serif;
}
</style>
</head>
<body class="bg-gradient-to-br from-blue-100 to-purple-100 flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-3xl shadow-2xl p-8 md:p-12 max-w-xl w-full text-center transform transition-all duration-500 hover:scale-105">
<div class="flex flex-col items-center">
<svg class="h-16 w-16 text-indigo-600 mb-4 animate-bounce" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9.75 18a.75.75 0 00.75.75h3a.75.75 0 00.75-.75v-1.5m-3.75 0V9.75m3.75 0V17m-3.75 0h3.75m-3.75 0h3.75m0 0a3 3 0 11-6 0 3 3 0 016 0zM12 21a9 9 0 100-18 9 9 0 000 18z" />
</svg>
<h1 class="text-5xl font-extrabold text-gray-800 mb-4">Hello from Innomax!</h1>
</div>
<p class="text-xl text-gray-600 mb-6">
This beautiful web application is hosted on an Amazon Linux EC2 instance.
</p>
<p class="text-md text-gray-500 mb-8">
The entire infrastructure for this page was defined as code with <span class="font-semibold text-teal-600">Terraform</span> and deployed automatically.
</p>
<!-- Social Links Section -->
<div class="flex flex-wrap justify-center gap-4 mb-8">
<a href="https://web.facebook.com/HugoClouds" target="_blank" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full shadow-lg transition-all duration-300 transform hover:scale-105">
Facebook
</a>
<a href="https://www.linkedin.com/in/saiminthu" target="_blank" class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full shadow-lg transition-all duration-300 transform hover:scale-105">
LinkedIn
</a>
<a href="https://www.youtube.com/@saiminthuu" target="_blank" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-full shadow-lg transition-all duration-300 transform hover:scale-105">
YouTube
</a>
<a href="https://www.notiz.life" target="_blank" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-full shadow-lg transition-all duration-300 transform hover:scale-105">
My App
</a>
</div>
<div class="relative inline-block w-full">
<button onclick="window.location.reload();" class="w-full md:w-auto bg-indigo-600 text-white font-bold py-3 px-8 rounded-full shadow-lg hover:bg-indigo-700 transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-indigo-300">
Refresh Page
</button>
</div>
</div>
</body>
</html>
- Add the file, commit the changes, and push it to your GitHub repository.
Bash
git add .
git commit -m "version 01"
git remote add origin https://github.com/SaiThuHugoCloud/innomax-web-app.git
git push origin master
We need to generate the ssh in our local VM.
ssh-keygen –t rsa –f ~/.ssh/my-innoweb-key
Note (The command ssh-keygen is a tool for creating, managing, and converting authentication keys for SSH.
ssh-keygen: This is the command that initiates the key generation process.
-t rsa: This flag specifies the type of key to create. rsa is a widely used and secure algorithm for generating key pairs. Other options include ed25519 and dsa.
-f ~/.ssh/my-innoweb-key: This flag specifies the filename and location where the key pair will be saved.
~/.ssh/: This is the standard, default directory for storing SSH keys on Linux and macOS. The ~ symbol is a shortcut for the current user's home directory.
my-innomax-key: This is the base name for the key files. The command will create two files:
my-innoweb-key (the private key)
my-innoweb-key.pub (the public key)
Step 2: Write Terraform Configuration Files
Create a new directory for your Terraform files and place the following files inside it.
variables.tf
variable "aws_region" { # Define variable for AWS region
description = "AWS region" # Description for documentation
type = string # Must be a string
default = "us-east-1" # Default region (N. Virginia)
}
variable "instance_type" { # Define variable for EC2 instance type
description = "EC2 instance type" # Used for VM size selection
type = string # Must be a string
default = "t2.micro" # Free-tier eligible small instance
}
variable "key_name" { # Define variable for EC2 key pair
description = "EC2 key pair name" # Key pair to connect via SSH
type = string # Must be a string
default = "my-innomax-key" # Default key pair name
}
variable "public_key_path" { # Define variable for local public key file path
description = "Path to public key file" # Path to .pub key used for EC2 login
type = string # Must be a string
default = "/home/saithu/.ssh/my-innomax-key.pub" # Default location of public key
}
variable "github_repo_url" { # Define variable for GitHub repository
description = "GitHub repo with web app" # Repository that stores web application code
type = string # Must be a string
default = "https://github.com/SaiThuHugoCloud/ innomax-web-app.git" # Default GitHub repo URL
}}
main.tf
terraform { # Configure Terraform settings
required_providers { # Define required providers
aws = { # Specify AWS provider
source = "hashicorp/aws" # Source of AWS provider (official)
version = "6.11.0" # Specific version of AWS provider
}
}
}
# AWS Provider configuration
provider "aws" {
region = var.aws_region # Use region from variable
profile = "saithu" # AWS CLI profile to use
}
# Load local public key file into Terraform
data "local_file" "public_key" {
filename = var.public_key_path # Path to public key (from variable)
}
# Create or import AWS Key Pair
resource "aws_key_pair" "generated_key" {
key_name = var.key_name # Key pair name (from variable)
public_key = data.local_file.public_key.content # Use local public key
lifecycle {
prevent_destroy = true # Prevent accidental deletion
}
}
# Get the latest Amazon Linux 2023 AMI
data "aws_ami" "amazon_linux" {
most_recent = true # Always fetch the newest version
owners = ["137112412989"] # Amazon official AMI account ID
filter { # Filter AMI by name pattern
name = "name"
values = ["al2023-ami-2023.*-x86_64"]
}
filter { # Filter by virtualization type
name = "virtualization-type"
values = ["hvm"]
}
}
# Fetch default VPC
data "aws_vpc" "default" {
default = true # Get the default VPC of account/region
}
# Get all subnets in the default VPC
data "aws_subnets" "public" {
filter {
name = "vpc-id" # Filter by VPC ID
values = [data.aws_vpc.default.id] # Match default VPC ID
}
}
# Choose first subnet from the list
locals {
public_subnet_id = tolist(data.aws_subnets.public.ids)[0]
}
# Create Security Group for web server
resource "aws_security_group" "web_sg" {
name = "web-server-sg" # Security Group name
description = "Allow HTTP, HTTPS, SSH, and ICMP"
vpc_id = data.aws_vpc.default.id
ingress { # Allow inbound HTTP (80)
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Open to all IPs
description = "HTTP from anywhere"
}
ingress { # Allow inbound HTTPS (443)
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS from anywhere"
}
ingress { # Allow inbound SSH (22)
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "SSH from anywhere"
}
ingress { # Allow ICMP (ping)
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow ICMP (ping)"
}
egress { # Allow all outbound traffic
from_port = 0
to_port = 0
protocol = "-1" # All protocols
cidr_blocks = ["0.0.0.0/0"] # To anywhere
}
tags = {
Name = "web-server-sg" # Tag for identification
}
}
# IAM role for SSM (to connect EC2 via AWS Systems Manager)
resource "aws_iam_role" "ssm_role" {
name = "ec2-ssm-role" # IAM role name
assume_role_policy = jsonencode({ # Trust policy for EC2
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com" # Allow EC2 to assume role
}
}]
})
lifecycle {
prevent_destroy = true # Protect from deletion
}
}
# Attach SSM Managed Policy to IAM role
resource "aws_iam_role_policy_attachment" "ssm_attach" {
role = aws_iam_role.ssm_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
# Create Instance Profile for EC2 to use IAM role
resource "aws_iam_instance_profile" "ssm_profile" {
name = "ec2-ssm-instance-profile-v2" # Name of instance profile
role = aws_iam_role.ssm_role.name # Attach SSM role
lifecycle {
prevent_destroy = true # Prevent accidental deletion
}
}
# Launch EC2 instance (web server)
resource "aws_instance" "web_server" {
ami = data.aws_ami.amazon_linux.id # Use latest Amazon Linux AMI
instance_type = var.instance_type # Instance type from variable
key_name = aws_key_pair.generated_key.key_name
vpc_security_group_ids = [aws_security_group.web_sg.id] # Attach Security Group
subnet_id = local.public_subnet_id # Place in first subnet
iam_instance_profile = aws_iam_instance_profile.ssm_profile.name # Attach IAM role
tags = {
Name = "innomax-web-server" # Tag for server
}
# User data script (runs on boot)
user_data = <<-EOF
#!/bin/bash
yum update -y # Update system
yum install -y nginx git # Install nginx and git
systemctl start nginx # Start nginx
systemctl enable nginx # Enable nginx on boot
cd /usr/share/nginx/html # Move to nginx web root
rm -rf * # Clear existing files
git clone ${var.github_repo_url} . # Clone website from GitHub
chown -R nginx:nginx /usr/share/nginx/html # Set permissions
EOF
}
# Allocate Elastic IP and attach to EC2
resource "aws_eip" "web_eip" {
instance = aws_instance.web_server.id
tags = {
Name = "innomax-web-eip" # Tag for Elastic IP
}
}
# Output the EC2 Public IP (Elastic IP)
output "web_server_public_ip" {
value = aws_eip.web_eip.public_ip # Show IP after apply
}
terraform.tfvars
This file allows you to specify variable values without modifying variables.tf.
Terraform
This file sets actual values for variables (overrides defaults in variables.tf).
It helps keep your config flexible without editing the main Terraform code.
aws_region = "us-east-1" # AWS region (N. Virginia)
instance_type = "t2.micro" # EC2 instance type (small, free-tier eligible)
key_name = "my-innoweb-key" # Name of existing EC2 key pair
public_key_path = "/home/saithu/.ssh/my-innoweb-key.pub" # Path to local public key
github_repo_url = "https://github.com/SaiThuHugoCloud/innomax-web-app.git"
# GitHub repo to clone into the web server
Step 3: Provision Infrastructure with Terraform
- Open your terminal and navigate to the directory containing your Terraform files.
- Initialize the Terraform project. This downloads the necessary AWS provider. terraform init
- Review the plan to see what Terraform will create. terraform plan
- Apply the configuration to create the AWS resources. terraform apply You will be prompted to confirm. Type yes and press Enter. Once the process is complete, Terraform will output the public IP address of your EC2 instance. Copy this IP address.
Step 4: Configure DNS for Your Domain
- Log in to your Z.COM domain registrar account.
- Navigate to the DNS management section for your domain, innomax.space.
- Create or modify an A record for your domain. o Host/Name: @ or innomax.space o Type: A o Value/IP Address: Paste the public IP address you got from the Terraform output. o TTL: Set a low TTL (e.g., 300 seconds) for faster propagation.
- Save the changes. It may take some time for the DNS changes to propagate globally (up to 24 hours, but often much faster).
Step 5: Test the Web Application
- After waiting a few minutes for DNS propagation, open your web browser.
- Navigate to your domain name, http://www.innomax.space.
- You should see the "Welcome to Innomax!” web page you created. This completes the hands-on lab. You have successfully deployed a web application using AWS, Terraform, Git, and GitHub.
Top comments (0)