In a previous post, we covered the process of hosting a Linux Apache web server on an AWS EC2 instance using Terraform.
In this post, we will extend our exploration to deploying a Windows-based infrastructure, specifically an Internet Information Services (IIS) web server on an AWS EC2 Windows instance. The steps involved in this process will be analogous to our earlier post, and we'll leverage Terraform modules to organize and manage the components of our infrastructure.
Architecture Overview
Before diving into the implementation details, let's briefly overview the architecture we'll be working with:
Step 1: Creating the VPC and Network Components
Our first step involves setting up the VPC and associated network components. The VPC module code will handle the creation of the VPC, Internet Gateway, public subnet, and the necessary route table and security group.
Variables used throughout the modules are mentioned in variables.tf file.
variables.tf
variable "aws_region" { type = string description = "AWS region to use for resources." default = "us-east-1" } variable "aws_azs" { type = string description = "AWS Availability Zones" default = "us-east-1a" } variable "enable_dns_hostnames" { type = bool description = "Enable DNS hostnames in VPC" default = true } variable "vpc_cidr_block" { type = string description = "Base CIDR Block for VPC" default = "10.0.0.0/16" } variable "vpc_public_subnets_cidr_block" { type = string description = "CIDR Block for Public Subnets in VPC" default = "10.0.0.0/24" } variable "instance_type" { type = string description = "Type for EC2 Instance" default = "t2.micro" } variable "instance_key" { default = "MyKeyPair" }
main.tf in VPC module
Create VPC
# Create the VPC resource "aws_vpc" "app_vpc" { cidr_block = var.vpc_cidr_block enable_dns_hostnames = var.enable_dns_hostnames }
Create internet gateway
# Create the internet gateway resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.app_vpc.id }
Create public subnet, route table and association
# Create the public subnet resource "aws_subnet" "public_subnet" { vpc_id = aws_vpc.app_vpc.id cidr_block = var.vpc_public_subnets_cidr_block map_public_ip_on_launch = true availability_zone = var.aws_azs } # Create the route table resource "aws_route_table" "public_rt" { vpc_id = aws_vpc.app_vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } } # Assign the public route table to the public subnet resource "aws_route_table_association" "public_rt_asso" { subnet_id = aws_subnet.public_subnet.id route_table_id = aws_route_table.public_rt.id }
Create security group which allows inbound SSH and HTTP traffic and all outbound traffic. (RDP 3389 port just to connect with windows instance remotely!)
# Create the security group resource "aws_security_group" "sg" { name = "allow_ssh_http" description = "Allow ssh http inbound traffic" vpc_id = aws_vpc.app_vpc.id ingress { from_port = 3389 to_port = 3389 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } ingress { description = "HTTP from VPC" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } }
Step 2: Launching a Windows EC2 Instance with IIS Web Service
With the foundational network components in place, we proceed to launch the EC2 instance using the Web module. This module will handle the instantiation of a Windows Server 2019 instance, configuring it to run an IIS web service, and displaying instance metadata on the website.
main.tf of WEB module
# Get latest Amazon Windows Server 2019 Ami data "aws_ami" "windows-2019" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["Windows_Server-2019-English-Full-Base*"] } } # Create the Linux EC2 Web server resource "aws_instance" "web" { ami = data.aws_ami.windows-2019.id instance_type = var.instance_type key_name = var.instance_key subnet_id = var.subnet_id security_groups = var.security_groups user_data = file("./modules/web/userdata.tpl") }
I have kept the user_data script in a separate file userdata.tpl
<powershell> Install-WindowsFeature -name Web-Server -IncludeManagementTools $instanceId = (Invoke-WebRequest -Uri http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsing).content $instanceAZ = (Invoke-WebRequest -Uri http://169.254.169.254/latest/meta-data/placement/availability-zone -UseBasicParsing).content $pubHostName = (Invoke-WebRequest -Uri http://169.254.169.254/latest/meta-data/public-hostname -UseBasicParsing).content $pubIPv4 = (Invoke-WebRequest -Uri http://169.254.169.254/latest/meta-data/public-ipv4 -UseBasicParsing).content $privHostName = (Invoke-WebRequest -Uri http://169.254.169.254/latest/meta-data/local-hostname -UseBasicParsing).content $privIPv4 = (Invoke-WebRequest -Uri http://169.254.169.254/latest/meta-data/local-ipv4 -UseBasicParsing).content New-Item -Path C:\inetpub\wwwroot\index.html -ItemType File -Force Add-Content -Path C:\inetpub\wwwroot\index.html "<font face = "Verdana" size = "5">" Add-Content -Path C:\inetpub\wwwroot\index.html "<center><h1>AWS Windows VM Deployed with Terraform</h1></center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>EC2 Instance Metadata</b> </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>Instance ID:</b> $instanceId </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>AWS Availablity Zone:</b> $instanceAZ </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>Public Hostname:</b> $pubHostName </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>Public IPv4:</b> $pubIPv4 </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>Private Hostname:</b> $privHostName </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "<center> <b>Private IPv4:</b> $privIPv4 </center>" Add-Content -Path C:\inetpub\wwwroot\index.html "</font>" </powershell>
Steps to Run Terraform
After creating the Terraform modules, we need to execute the Terraform commands to deploy the infrastructure:
terraform init terraform plan terraform apply -auto-approve
Once the terraform apply completed successfully it will show the public ipaddress of the Windows IIS web server as output
Apply complete! Resources: 7 added, 0 changed, 0 destroyed. Outputs: instance_id = "i-0af8c526023ab3d7d" public_ip = "http://44.205.246.179/"
Running Website
And there you go – a basic website running on an EC2 Windows instance in AWS created using Terraform.
Accessing windows server using RDP:
Cleanup
Remember to stop AWS components to avoid large bills.
terraform destroy -auto-approve
In the upcoming module, we'll take our deployment a step further by exploring CloudWatch alarms with SNS email notifications, enhancing the monitoring capabilities of our AWS environment. Happy Coding!
Resources
GitHub Link: https://github.com/chinmayto/terraform-aws-windows-webserver
EC2 Documentation: https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/concepts.html
Top comments (0)