DEV Community

Cover image for Getting Started with AWS and Terraform: Deploying a Windows IIS Web Server on AWS EC2 Instance using Terraform
Chinmay Tonape
Chinmay Tonape

Posted on • Updated on

Getting Started with AWS and Terraform: Deploying a Windows IIS Web Server on AWS EC2 Instance using Terraform

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:

Windows IIS Web Server on AWS EC2

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"
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

Create internet gateway

# Create the internet gateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.app_vpc.id
}
Enter fullscreen mode Exit fullscreen mode

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
}

Enter fullscreen mode Exit fullscreen mode

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"]
  }
}
Enter fullscreen mode Exit fullscreen mode

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")
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/"
Enter fullscreen mode Exit fullscreen mode

Running Website

And there you go – a basic website running on an EC2 Windows instance in AWS created using Terraform.

Windows IIS Web Server on AWS EC2

Windows IIS Web Server on AWS EC2

Accessing windows server using RDP:

Windows IIS Web Server on AWS EC2

Cleanup

Remember to stop AWS components to avoid large bills.

terraform destroy -auto-approve
Enter fullscreen mode Exit fullscreen mode

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)