Launching WebServer on AWS using Terraform and Jenkins

RAJNISH MISHRA
6 min readJun 12, 2020

Amazon Web Service (AWS) is a platform provided by Amazon for on demand Cloud Computing. But creating any infrastructure using CLI or GUI is not a good option.

So, I have created a webserver on top of aws instance with the help of Terraform and Jenkins. Almost every thing is automated.

For understanding the project, you need some prior knowledge.

Before starting with the project, you should have following things

  • AWS account
  • IAM user created
  • AWS CLI tool installed
  • Terraform installed
  • Environment variable set for Terraform

AWS Configure

aws configure
AWS Access Key ID [****************L4P7]:
AWS Secret Access Key [****************4PEs]:
Default region name [ap-south-1]:
Default output format [None]:

Terraform

provider "aws" {
region = "ap-south-1"
profile = "IAM_username"
}

Here, we provide the region where we want to use the services and we also provide IAM user.

  1. Creating Key
resource "tls_private_key" "prkey" {
algorithm = "RSA"
}
resource "aws_key_pair" "webkey1" {
key_name = "webkey1"
public_key = tls_private_key.prkey.public_key_openssh
}

Here, we create the key pair which will help to login.

2. Creating Security Group

resource "aws_security_group" "allow_80" {
name = "allow_80"
description = "Allow port 80"
ingress {
description = "incoming http"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "incoming ssh"
from_port = 22
to_port = 22
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"]
}
tags = {
Name = "allow_80"
}
}

Here, we will allow different ports for different purpose

  • Port 80 for webserver
  • Port 22 for remote login i.e. SSH

3. Creating Instance

resource "aws_instance" "webserver" {
ami = "ami-052c08d70def0ac62"
instance_type = "t2.micro"
availability_zone = aws_ebs_volume.web_volume.availability_zone
key_name = "webkey1"
security_groups = ["${aws_security_group.allow_80.name}"]
tags = {
Name = "WebOS"
}
}

This will create instance.

4. Creating EBS

resource "aws_ebs_volume" "web_volume" {
availability_zone = "ap-south-1a"
size = 1

tags = {
Name = "web_volume"
}
}

We will create this EBS storage to store web pages permanently

5. Attaching Volume

resource "aws_volume_attachment" "ebs_att" {
device_name = "/dev/sdr"
volume_id = aws_ebs_volume.web_volume.id
instance_id = aws_instance.webserver.id
force_detach = true
}

We attach the volume to out instance

6. Creating S3 Bucket

resource "aws_s3_bucket" "s3bucket" {
bucket = "poiuytrewqlkjhgfdsa"
acl = "private"

tags = {
Name = "s3bucket"
}
}
resource "aws_s3_bucket_public_access_block" "s3type" {
bucket = "${aws_s3_bucket.s3bucket.id}"
block_public_acls = true
block_public_policy = true
}
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
depends_on = [aws_s3_bucket.s3bucket]
}
data "aws_iam_policy_document" "s3_policy" {
statement {
actions = ["s3:GetObject"]
resources = ["${aws_s3_bucket.s3bucket.arn}/*"]
principals {
type = "AWS"
identifiers = [ aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn ]
}
}
}
resource "aws_s3_bucket_policy" "policy" {
bucket = aws_s3_bucket.s3bucket.id
policy = data.aws_iam_policy_document.s3_policy.json
}

Here, we create S3 bucket for storing images and prohibit users from doing any activity on s3.

By creating policy we only allow CloudFron to read objects from S3.

7. Creating CloudFront

locals {
s3_origin_id = "myS3Origin"
}
resource "aws_cloudfront_distribution" "webcloud" {
origin {
domain_name = "${aws_s3_bucket.s3bucket.bucket_regional_domain_name}"
origin_id = "${local.s3_origin_id}"
s3_origin_config{
origin_access_identity = aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "${local.s3_origin_id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
resource "null_resource" "wepip" {
provisioner "local-exec" {
command = "echo ${aws_instance.webserver.public_ip} > publicip.txt"
}
}

This will create a CloudFront Service that provides as a CDN.

8. Mounting Volume and Installing required softwares

resource "null_resource" "imp_soft"  {
depends_on = [aws_instance.webserver,
aws_volume_attachment.ebs_att]
connection {
type = "ssh"
user = "ec2-user"
private_key =tls_private_key.prkey.private_key_pem
host = aws_instance.webserver.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo yum install httpd -y",
"sudo yum install php -y",
"sudo systemctl start httpd",
"sudo systemctl enable httpd",
"sudo yum install git -y",
"sudo setenforce 0"
]
}
}
resource "null_resource" "mount" {
depends_on = [aws_volume_attachment.ebs_att,
null_resource.imp_soft]
connection {
type = "ssh"
user = "ec2-user"
private_key =tls_private_key.prkey.private_key_pem
host = aws_instance.webserver.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo mkfs.ext4 /dev/xvdr",
"sudo mount /dev/xvdr /var/www/html",
"sudo rm -rf /var/www/html/*",
"sudo git clone https://github.com/Rajnish-TheGreat/web_code.git /var/www/html/"
]
}
}

Remote ssh login is performed and the volume is mount to /var/www/html and the website code is copied to the same folder. Now, our code is ready to be compiled

Terraform With Jenkins

This Job automatically downloads the Terraform code from the GitHub and build the infrastructure.

Uploading image to S3

  • Install S3 Publisher plugin

Go to Manage Jenkins and select Configure System. look for Amazon S3 Profiles.

Please provide a profile name, access key and secret access key for your AWS account. also, Create an IAM user with the relevant S3 Permissions.

  • Configure job

Website

This is final output of the very basic website which is almost fully automated.

The amount of error, I encountered while making this project was too much. So, I may have missed to explain few steps

In case of any queries or suggestions, DM me or comment below.

Thank You for your valuable time

--

--