Automate AWS VPC and EC2 Setup with CloudFormation

User Icon By Azam Akram,   Calendar Icon February 1, 2025
aws-vpc-ec2-webserver-cloudformation-stack

Setting up an AWS VPC and launching an EC2 instance to host a web server is a fundamental step in deploying cloud applications. However, manually configuring these resources through the AWS Management Console is not only time-consuming but also prone to errors, especially when repeating the process multiple times. AWS CloudFormation simplifies this by enabling Infrastructure as Code (IaC), allowing us to automate resource provisioning with a single, reliable, and repeatable deployment.

In this blog, we will create a CloudFormation template in YAML format that automates the setup of a VPC and essential networking components, enabling the deployment of an EC2 instance with a pre-configured web server.

By the end of this excercise, you will:

  • Create a VPC with a public subnet
  • Attach an Internet Gateway and define routing rules
  • Configure a Security Group for HTTP and SSH access
  • Launch an EC2 instance with a running Apache web server
  • Test the instance and clean up resources

Prerequisites

Before we move ahead please consider following,

  • You will need an AWS account. If you don’t have one, this guide will walk you through setting up a free-tier AWS account.
  • Generate aws access keys to configure local CLI environment. The access keys are required to deploy the CloudFormation stack using the AWS CLI. Section 9 of this blog explains that process.
  • In a separate blog, I have written the exact same process of setting up a VPC and deploying a web server on an EC2 instance using the AWS Management Console.

For the sake of explaination I will provide cloudformation snipet to create relevant resources in a separate section, but you need to write all of these cloudformation blocks in one file, let's name it aws_vpc_ec2_setup.yaml.

Let's start!

Creating a VPC

A Virtual Private Cloud (VPC) allows you to define a private network within AWS. The following CloudFormation snippet creates a VPC with DNS support enabled:

MyVPC:
  Type: AWS::EC2::VPC
  Properties:
    CidrBlock: 10.0.0.0/16
    EnableDnsSupport: true
    EnableDnsHostnames: true
    Tags:
      - Key: Name
        Value: My-VPC

Creating a Public Subnet

A public subnet allows resources to be accessible from the internet. The following snippet creates a public subnet and enables auto public IP assignment:

MyPublicSubnet:
  Type: AWS::EC2::Subnet
  Properties:
    VpcId: !Ref MyVPC
    CidrBlock: 10.0.1.0/24
    MapPublicIpOnLaunch: true
    AvailabilityZone: !Select [ 0, !GetAZs "" ]
    Tags:
      - Key: Name
        Value: my-public-subnet

Note: VpcId: !Ref MyVPC refers to VPC created in previous section

Attaching an Internet Gateway

An Internet Gateway is required to enable internet access for instances in a public subnet.

MyInternetGateway:
  Type: AWS::EC2::InternetGateway
  Properties:
    Tags:
      - Key: Name
        Value: my-internet-gateway

AttachGateway:
  Type: AWS::EC2::VPCGatewayAttachment
  Properties:
    VpcId: !Ref MyVPC
    InternetGatewayId: !Ref MyInternetGateway

Configuring a Route to the Internet Gateway

For our public subnet to communicate with the internet, we must update its route table. First we create a new router table MyRouteTable, then create a new route MyRoute and finally associate route table to subnet, SubnetRouteTableAssociation.

MyRouteTable:
  Type: AWS::EC2::RouteTable
  Properties:
    VpcId: !Ref MyVPC
    Tags:
      - Key: Name
        Value: My-Routing-Table

MyRoute:
  Type: AWS::EC2::Route
  DependsOn: AttachGateway
  Properties:
    RouteTableId: !Ref MyRouteTable
    DestinationCidrBlock: 0.0.0.0/0
    GatewayId: !Ref MyInternetGateway

SubnetRouteTableAssociation:
  Type: AWS::EC2::SubnetRouteTableAssociation
  Properties:
    SubnetId: !Ref MyPublicSubnet
    RouteTableId: !Ref MyRouteTable

Creating a Security Group

To allow inbound HTTP (port 80) and SSH (port 22) traffic, we define a Security Group:

MySecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Allow HTTP and SSH traffic
    VpcId: !Ref MyVPC
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0
    Tags:
      - Key: Name
        Value: My-Web-Server-SG

As we are going to run a public web server in ec2 instance, we allow tcp connection for HTTP (port 80) from all IP addresses 0.0.0.0/0 in inbound rules for subnet.

We also want to connect ec2 instance via ssh, that's why we have defined an inbound rule to access SSH port 22 from all IP addresses (anywhere).

Launching an EC2 Instance

The EC2 instance will be created in the public subnet and configured to run a basic web server.

MyEC2Instance:
  Type: AWS::EC2::Instance
  Properties:
    InstanceType: t2.micro
    ImageId: ami-0c55b159cbfafe1f0
    SubnetId: !Ref MyPublicSubnet
    SecurityGroupIds:
      - !Ref MySecurityGroup
    Tags:
      - Key: Name
        Value: My-WebServer-Ec2-Instance
    UserData:
      Fn::Base64: |
        #!/bin/bash
        yum update -y
        yum install -y httpd
        systemctl start httpd
        systemctl enable httpd

Note: I set AMI ImageId: ami-0c55b159cbfafe1f, but you need to write AMI according to your region.

Deploying the CloudFormation Stack

To deploy this CloudFormation stack, use the following AWS CLI command:

aws cloudformation deploy \
  --stack-name my-vpc-ec2-stack \
  --template-file aws_vpc_ec2_setup.yaml \
  --capabilities CAPABILITY_NAMED_IAM

After successful deployment, retrieve the EC2 instance’s public IP:

aws cloudformation describe-stacks \
  --stack-name my-vpc-ec2-stack \
  --query "Stacks[0].Outputs"

You can also check cloudformation creation timeline,

Testing the EC2 Instance

Test HTTP Access

Copy the Public IP Address of your instance and open it in a web browser. If everything is set up correctly, you should see the default web page.

Test SSH Access

To connect via SSH:

ssh ec2-user@<PUBLIC_IP>

Test using Connect

In AWS EC2 Management console page, select Connect to connect with ec2 instance via ssh,

Cleaning Up Resources

To delete all resources, run:

aws cloudformation delete-stack --stack-name my-vpc-ec2-stack

Download Cloudformation Template

You can download the full cloudformation template from here.

Conclusion

In this blog, we automated the creation of an AWS VPC, set up networking, configured security, and launched an EC2 instance using CloudFormation. This Infrastructure as Code approach simplifies deployment and ensures consistency across environments.