In this note, I detail all the steps required to create a bare-bone web server on AWS EC2. I discuss from creating the VPC, subnets, internet gateway, security group, and EC2 instances to finally automating 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 AWS EC2 instance. However, those were cases where the 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, AWS VPC, subnets, internet gateway, security groups, route table, 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 AWS 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 AWS 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-aws-ec2-user-data-and-terraform.
Step 4: Create an AWS EC2 instance with a user data file
This is the last step where I provisioned a couple of EC2 instances (the above image is of only one 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
These are the public DNS of the three EC2 instances that Terraform provisioned.
However, on the AWS console, I found the two EC2 instances were still initializing. That is because Terraform does not manage the state of the 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 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 the 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 AWS 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 EC2 instances in my subsequent note at -add-an-application-load-balancer-to-aws-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.