top of page
Search

🚀Deploy EC2 on AWS with Terraform & GitHub Actions (End‑to‑End Guide)

  • Writer: Mohammed  Juyel Haque
    Mohammed Juyel Haque
  • Aug 25
  • 2 min read

Spin up a production‑ready EC2 instance from a GitHub repo using Terraform.


ree

📂 Project Structure

Here’s the recommended folder layout:

.

├── .github

│ └── workflows

│ └── deploy.yml # GitHub Actions workflow

├── infra

│ ├── main.tf # Root Terraform config

│ ├── variables.tf

│ ├── outputs.tf

│ └── terraform.tfvars # Variables values

└── modules

└── ec2

├── main.tf

├── variables.tf

└── outputs.tf


Github Actions(deploy.yaml)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-terraform-state-bucket1ju",
        "arn:aws:s3:::my-terraform-state-bucket1ju/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:*"
      ],
      "Resource": "*"
    }
  ]
}

Terraform: backend & provider (infra/providers.tf)

terraform {

backend "s3" {

bucket = "my-terraform-state-bucket1ju"

key = "ec2/terraform.tfstate"

region = "us-east-1"

encrypt = true

}

}

provider "aws" {

region = var.region

}


Terraform: variables (infra/variables.tf)

variable "region" {

description = "AWS region"

type = string

default = "us-east-1"

}


variable "instance_type" {

description = "EC2 instance type"

type = string

}


variable "ami_id" {

description = "AMI to use"

type = string

}


variable "key_name" {

description = "SSH key name"

type = string

}


Terraform: main call the ec2 module (infra/main.tf)


module "ec2_instance" {

source = "../modules/ec2"

instance_type = var.instance_type

ami_id = var.ami_id

key_name = var.key_name

}


Terraform: outputs (infra/outputs.tf)


output "ec2_public_ip" {

description = "Public IP of the EC2 instance"

value = module.ec2_instance.public_ip

}


tfvars (env/terraform.tfvars)


region = "us-east-1"

instance_type = "t2.micro"

ami_id = "ami-00ca32bbc84273381"

key_name = "test-key"


Terraform: module variables (modules/ec2/variables.tf)


variable "ami_id" {

description = "AMI id for the EC2 instance"

type = string

}


variable "instance_type" {

description = "EC2 instance type"

type = string

default = "t3.micro"

}


variable "instance_name" {

description = "Tag Name for instance"

type = string

default = "terraform-ec2-juyel"

}


variable "subnet_id" {

description = "Subnet ID to launch the instance into"

type = string

default = null

}


variable "security_group_ids" {

description = "List of security group ids"

type = list(string)

default = []

}


variable "key_name" {

description = "SSH key name to attach (optional)"

type = string

default = null

}


variable "tags" {

description = "Additional tags"

type = map(string)

default = {}

}


Terraform: module outputs (modules/ec2/outputs.tf)


output "instance_id" {

description = "EC2 instance id"

value = aws_instance.this.id

}


output "public_ip" {

description = "EC2 public IP"

value = aws_instance.this.public_ip

}


output "private_ip" {

description = "EC2 private IP"

value = aws_instance.this.private_ip

}


Terraform: main resource (modules/ec2/main.tf)


resource "aws_instance" "this" {

ami = var.ami_id

instance_type = var.instance_type

subnet_id = var.subnet_id

key_name = var.key_name


vpc_security_group_ids = var.security_group_ids


tags = merge(

{

Name = var.instance_name

},

var.tags

)

}


IAM Role Policy:


{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-terraform-state-bucket1ju",
        "arn:aws:s3:::my-terraform-state-bucket1ju/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:*"
      ],
      "Resource": "*"
    }
  ]
}








 
 
 

Recent Posts

See All

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating*

© 2024 Mohammed Juyel Haque. All rights reserved.

bottom of page