Create a web-server on Amazon EC2 instance using Terraform and user data

In this note, I detail all the steps required to create a bare-bone web server on Amazon EC2. I discuss creating the Amazon Virtual Private Cloud, subnets, internet gateway, security group, and Amazon EC2 instances to finally automate the process via Terraform and user data.

Note: I did not include the concepts of load balancing, installing a certificate, or route53 in this note. At the end of this note, I have a link to my following note, where I added an application load balancer into the configuration.

A few youtube videos or blogs are available on how to host a website on an Amazon EC2 instance. However, those were cases where the Amazon EC2 was hosted on the default VPC or created via the AWS console. Nothing wrong with that. But I wanted to create the web servers right from the ground up, and that too using Terraform; hence to capture my thought process, I came up with the idea of writing this note.

You will need a basic understanding of Terraform, Amazon VPC, subnets, internet gateway, security groups, route table, Amazon EC2, and user data to follow along. If you are new to these concepts, you can read about getting started with Terraform and about how to create an Amazon EC2 instance and underlying infrastructure (like vpc, subnets, etc) using Terraform.

If you want to walk along, I have the code committed to my GitHub repository: add-aws-elb-ec2-terraform.
I broke down this use case into four steps.

Step 1: Create the network components
As you can see, I created a pretty small VPC since this was a proof of concept. Notably, there were two flags that I set to true. You can read them at AWS-Docs: Setting Up DNS in Your VPC. The rest of the infrastructure bits are pretty standard; hence, I did not expand them in the image below. If you want to know more, please refer to this note.
Please note that the use-case for that post and this post are slightly different. Here, I did not create the network interface and the associate elastic IP; instead, I depended on AWS to manage that for me.
Step 2: Create a security group
Since this was a proof of concept and since I did not require HTTPS traffic, I did not bother to create more than what was necessary.

Step 3: Create the user data file
User data is a feature that allows customization of Amazon EC2 (virtual machine) when it is provisioned and (if desired) with each restart. I was required to install the httpd service and update the index.html page in this use case. I have a detailed note on user data at working-with-amazon-ec2-user-data-and-terraform

Step 4: Create an Amazon EC2 instance with a user data file
This is the last step, where I provisioned a couple of Amazon EC2 instances (the above image is of only one Amazon EC2 instance) using the infrastructure bits discussed earlier. An interesting observation is that since I required the instances accessible from outside the VPC, I had to associate them with a public IP address.

With all the above code, I ran the usual Terraform commands of terraform apply (after initializing the repository). And after Terraform provisioned the resources, I received the message below. That is due to the specification in the output block (in the file).
These are the public DNS of the three Amazon EC2 instances that Terraform provisioned.
However, on the AWS console, I found the two Amazon EC2 instances were still initializing. That is because Terraform does not manage the state of the Amazon EC2 instance after it provisions them, and the control passes over to the user data file. Stated differently, Terraform does not track whether the user data script was successful or not. However, I was confident that the user-data file I provided was correct (I’d run this code more than a few dozen times in the past). Therefore, I waited for the instances to pass the status checks before I tried to access the public DNS that Terraform provided.
Since I did not install a certificate on the Amazon EC2 instances, HTTPS was not going to work, and I tried the HTTP URL, which was HTTP://$(the public DNS provided in the output)
And this is what I saw for all three public DNS addresses.
The “Not secure” right before the public DNS name denotes that this is an HTTP URL.
And that brings us to the end of this note on how to provision a web server on an Amazon EC2 instance using Terraform and user data.

If you are familiar with Terraform, go ahead and fork the repository and try it. Then, let me know if you face any challenges. I also added an application load balancer to the three Amazon EC2 instances in my subsequent note at  -add-an-application-load-balancer-to-amazon-ec2-using-terraform.

Please note that I did not discuss the security aspect of managing the secret key and access key in this note. There are two methods I am comfortable with storing the values in the terraform.tfvars file OR passing them through the command line with terraform command. You can decide which option is secure and manageable depending on your use case and security posture.

4 thoughts on “Create a web-server on Amazon EC2 instance using Terraform and user data

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s