Deploy an Nginx Web Server on an EC2 instance with Terraform
Tags: aws, nginx, terraform, devops
Published: 2022-09-19 13:11:11

In this tutorial, you will learn how to automatically deploy an Nginx Web Server on an EC2 instance, with Terraform.


## Prerequisites
1. An active AWS account with an IAM user already created
2. Text editor of your choice (VSCode Recommended)
3. Terraform Installed, you should also have a basic knowldge of how it works.
4. Bash scripting knowledge

As you should know by now, Terraform is an IaC tool that helps to automate processes which increase delivery time of software. In this tutorial, Terraform will be employed in setting up an ec2 instance and deploying an nginx web server on it using bash scripts which will be provided.

## Setting up project environment

First step is to create a folder on your device and open it up in VSCode. We will be creating 3 terraform files for this project;
- terraform.tfvars
- module.tf
- userdata.tpl


### 1. Terraform.tfvars
Run the below command to create your `terraform.tfvars` file
```
touch terraform.tfvars
```
Your `terraform.tfvars` file is going to contain private information that shouldn't be shared with the public. In the file, copy and paste the below configuration.
```
# Private information
aws_access_key = ""
aws_secret_key = ""
key_name = "demokey"
private_key_path = "./demokey.pem"
```
- Your access and secret key should be filled in. You can get that from the IAM user you created.

- The `key_name` is the name of the key which will be used to ssh into your instance. If you have an existing one you can use that. If you don't, lets create one together.

**Creating Key**
In your AWS console, search for key pair and click on it.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xla8x8wec13lkygx7we2.png)


After selecting it, Click on `Create key pair`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tjdxg15g48dbxdzznhye.png)


Give your key pair a name that way you can always search for it easily when needed. Also, change key file format from ".ppk" to ".pem" because we need it in a ".pem" state. Add a tag if you wish to, but that is optional and proceed to create the key pair.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ffjrt6u1hkbx4jas5hi.png)

**Copy the Key**
The just created key pair would be automatically downloaded on your device. It needs to be copied to the working directory for ease of use. In your terminal, run the command
```
cp ~/Downloads/demokey.pem ./
```
This command basically copies your keypair from its current directory to your working directory. 
- `cp` is to copy and `~/Downloads/demokey.pem` is the directory where my key pair currently is, `demokey` is the name of my key pair. Be sure to specify the directory of your own key pair and don't forget to add the extension `.pem`.

- `./` means your current working directory, or in other words, where you currently are and want to key pair to be copied to.

- For the `private_key_path` in the `terraform.tfvars file`, type in the path of your key. It should look like this `./demokey.pem`. Remember to replace the `demokey` with your key's name.

### 2. Module.tf
To create your `module.tf` file, run the below command in your terminal

```
touch module.tf
```
Inside the `module.tf file`, copy and paste the below Terraform configurations
```
# Variables
variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "key_name" {}
variable "private_key_path" {}
variable "region" {
  default = "us-east-1"
}


# Provider
provider "aws" {
  region  = var.region
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
}


# DATA
data "aws_ami" "aws_ubuntu" {
  most_recent = true
  owners      = ["amazon"]

 filter {
    name   = "name"
    values = ["amzn-ami-hvm*"]
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}


# RESOURCES
# Ami

resource "aws_instance" "aws_ubuntu" {
  instance_type          = "t2.micro"
  ami                    = "ami-052efd3df9dad4825"
  key_name               = var.key_name
  user_data              = file("userdata.tpl")
}  


# Default VPC
resource "aws_default_vpc" "default" {
  
}

# Security group
resource "aws_security_group" "demo_sg" {
  name        = "demo_sg"
  description = "allow ssh on 22 & http on port 80"
  vpc_id      = aws_default_vpc.default.id

  ingress {
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  ingress {
    from_port        = 80
    to_port          = 80
    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"]
  }
}



# OUTPUT
output "aws_instance_public_dns" {
  value = aws_instance.aws_ubuntu.public_dns
}
```

- The variable section consists of the variables you created in the terraform.tfvars file
- The provider section contains information of your provider, region and information which connects terraform to your AWS account. **Be sure to specify the region you are making use of in AWS**. In my case I am using the N.Virginia region (us-east-1)
- The data section contains information of your instance. 
Data sources are like read-only references in Terraform. They aren’t resources in the sense that they create anything, but they can be referenced by actual resources to pull information from AWS where applicable.
- The resources section contains information of your ami, VPC and security group. You can modify this depending on your use case.
- The output section is basically what you want to be printed to the screen after your resources have been created. In this case, your instance's public dns would be printed out for you.




### 3. Userdata.tpl
To create your userdata.tpl file, run the below command in your terminal

```
touch userdata.tpl
```
This file will contain the bash script which will install nginx on your instance.

```
#!/bin/bash
sudo apt update -y &&
sudo apt install -y nginx
echo "Hello World" > /var/www/html/index.html
```

The above bash script will be automatically ran immediately the instance is created and it starts running. We are basically updating "apt", configuring NGINX to be installed on boot of the instance and instructing it to echo an "Hello World" message to us by overwriting NGINX's index.html file. `var/www/html/index.html` is the path to the NGINX's index.html file.


Keep in mind that you can modify the echo output to what you want. It could be echo "Hi, how are you doing?", anything of your choice.

Also, if you notice in the module.tf file, under the resources ami section, the user data file was defined. This basically links your user data file to the instance you are creating so that nginx would be installed on the instance.

## Run the terraform files
Save your files and run 
```
terraform init
```
This will initialize your directory and install necessary plugins needed. It is the first command that has to be run after writing a new terraform configuration.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s2xe9hsws2dng9nl4mxr.png)



After initialization run

```
terraform validate
```

The above commands checks your terraform configuration files for errors.



![terraform validate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrucix8q9btyscfj35f0.png)

Next command to run is the `terraform plan`
```
terraform plan
```
This would show you the steps or execution plan that terraform wants to take.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/asktrtuahg2464a8mnm0.png)


Next, run 
```
terraform apply
```
This command carries out the plan and creates your infrastructure for you.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m47agx3bgp591yub9hlu.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7roi7i3o5m5gq9rdppfa.png)



You can see the output dns which you asked terraform to print to your screen.

Copy and paste the output dns on a webpage and you should see your echo output message from the bashcript you wrote earlier on.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/flyipgqk3gbk91wyifvx.png)



NB: It might take a while since all the scripts have to be executed "one by one"


### Running checks
Navigate to your AWS account and check under ec2 instance, your instance should be running.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7mp53ag4f20nvlctsac.png)


If your echo message/ NGINX doesn't load when paste your instance's DNS on the web, proceed to check if Nginx is running.

In your AWS Console under instances, select your running instance 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tr8u6fj1izootls9dsze.png)
Click on the "Connect" button

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0m1kn5n12mg47j00qsn.png)
Copy and paste the "example" link into your terminal

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/axadb9lkptthq1z70iug.png)


Now you're logged in, run the command
```
systemctl status nginx
```
and you should get the below output



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcaet070amzia8k6onre.png)

This verifies that nginx is running. 

To exit from your instance, run the below command

```
exit
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ms371oo7rzptpxm5brk3.png)

And that's it!!

You can delete your resources with the below command
```
terraform destroy -auto-approve
``` 

## Conclusion

In this article, we deployed an Nginx web server on an ec2 instance immediately it was created, all automatically with Terraform.