Creating a Custom VPC

Dane Forslund
8 min readJun 21, 2022

Provisioning a VPC to fit your needs…

There are many ways to build your VPC, and my hope is that as you follow along you are able to better navigate the process to fit your needs.

For our purposes today we will be creating a VPC that uses:

2 subnets in two different availability zones — (1 public and 1 private)

2 routing tables — (1 for each subnet)

An Internet Gateway and NAT Gateway

A set of autoscaling EC2’s in the public subnet

An instance in the private subnet

We will create, modify, and execute these services and show that it worked at the end…

Note: In this project, if I used BOLD font, it is likely an option you can select in the console. 

Lets Begin!

In the AWS console, find your way to the VPC dashboard. From there go ahead and click “Create VPC”. Although there is a great option for “VPC and more”, where you can add multiple services from the same dashboard, we will use “VPC only”, so we can see what we are doing each step of the way.

Go ahead and name your VPC (mine is “Custom-1”), and then we will need to include our IPv4 CIDR block. We will use IPv4 CIDR: as this will give us the largest CIDR range.

Although you can include an IPv6 CIDR block, we will not. You can also change the Tenancy option if you need to, but to be cost effective we will leave this as “default”, which is the shared hardware option. 

Finish this by choosing, “Create VPC”. When you have succesfully created your VPC, you also happened to initiate a few other services! You should now see that you have a Network ACL, a Default Routing Table, and a Default Security Group, but we will need to add our subnets, internet gateway, another routing table, a NAT Gateway, and make a few modifications along the way.

Let’s continue by creating our subnets…

From the left hand dropdown menu in your VPC dashboard you should find the “Subnets” page, and click “Create subnet”.

You will need to make sure you choose the correct VPC, again mine is “Custom-1”, and then we will make our subnets. I am going to identify mine by the IPv4 CIDR Block they have, and the name of their availability zone. This is a great way to keep track of what these subnets are created for, but feel free to name yours whatever your heart desires (within the parameters AWS gives).

For example, my first subnet has a IPv4 CIDR block of, and it is in us-east-1a. It will be named “ — us-east-1a”, and my second one has a IPv4 CIDR block of, and it is in us-east-1b and will be named “ — us-east-1b”. When these are configured, click “Create subnet”.

Note: A CIDR block is basically used to allocate IP addresses and routing. Two subnets cannot have the same CIDR block within the same VPC.

When these are finished, we will need to modify one of them to “enable auto-assign public IPV4 address”, as this is not a default setting. Do this in the subnet you plan to make public. Click the subnet, go to “actions”, and then choose “Edit subnet settings”. On this new page, check the box and save!

Now let’s add our Internet Gateway…

Again, this page is on the left side drop down menu on our dashboard, and you can choose “Create Internet Gateway”. Name it what best suits you, and choose “Create Internet Gateway” again. Then under “Actions” select “Attach to VPC” and finalize your action by clicking the “Attach internet gateway” button.

Next lets check our Routing Tables…

Although we have a default routing table made, we will need to create a second one for our public subnet. Choose the “Route Tables” page from the drop down menu on the left, and select “Create route table”. Select the correct VPC, and click “Create route table”. On this next page, choose “Subnet Associations” and “Edit subnet associations” to add our public subnet to this routing table.

Note: Although your private subnet will be associated to your VPC by default, I usually repeat this process with the private subnet and our new VPC anyways. - Gives me peace of mind haha

Now go into your public route table, and under “Routes”, choose “Edit routes”, and we are going to add a rule that gives us access to the internet gateway. It should look similar to this:

Go ahead and “save changes”.

Next we will add a NAT Gateway…

Choose the “NAT gateway” page on the drop down menu, and select “Create NAT gateway”. Name your NAT Gateway, and select your public subnet. After this, select “Allocate Elastic IP” and then “Create NAT gateway”. After the state of your NAT gateway changes from “pending” to “Available”, lets go back to our Route Tables…

Note: Your NAT gateway may take a few minutes to become "Available".

When you make your way back to the route tables, select your private route table and choose “Routes” and “Edit routes”. Add a new rule that allows all access out through your new NAT gateway. It should look like this:

Save your changes, and then —

Make your way to the EC2 Dashboard…

From here I am going to create a Launch Template. There will be a page for this on the left hand drop down menu and you can select “Create launch template”.

Note: you could do something similar to this in your private subnet as well, but I plan to use a single private EC2 instance instead. 

Go ahead and name your template, and then you can customize your Machine Image. I plan to use the “Quick Start” option and will go with “Amazon Linux” and the “t2.micro Free tier eligible” instance type. I will use an existing “Key pair”, but you can create one of your own if you’d like. Then select your public subnet and then the “Create security group” option. Name it, mine is “CustomWebDMZ”, and add your security rules to look like this:

This will allow public access…

When you have added these, select “Advanced details” and make your way to the bottom of the page. Here we will add our User data, which installs and enables an NGINX server, through this bash script:

sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx

Finally, select “Create launch template” and make your way to the “Auto Scaling Group” page and choose “Create Auto Scaling group”. Name it, and select your template. Choose “Next”, select the correct VPC, then the public subnet and availability zone. Choose “Next” again, and then if you’d like you can add a load balancer, but for our purposes we will not. Scroll down and select “Next”.

Select your desired capacity, minimum capacity, and maximum capacity. Mine will look like this:

Then Give it a CPU utilization target tracking policy of 50%, so that we can test the autoscaling later…

After that, select “Next”, and on the next page do that again, then again, and complete this by choosing “Create Auto Scaling group” on the last page.

Now let’s go to the “Instances” page, and launch a new instance. Select “Launch Instances”, name it, and through the quick start options make it the same build as the public instances.

Note: I will be adding a Key Pair to my private instance, and will have the key available on my public subnet. This is not a wise security strategy, but for my purposes we will do this to show that we can successfully connect to it through our public subnet. I did this by copying and pasting the key info into a new "_____.pem" file using Vim. 

We will select “Create security group”, and only select “Allow SSH…” with a “Custom” option from our public subnet CIDR ( Finally, “Launch instance”…

Now lets check our work…

We will check our public website by going to the public EC2 instance and selecting the “Public IPv4 address” and pasting it into a new tab.


Now lets check the Auto Scaling, by stressing the EC2 instance through the command line. Go into an instance and select “connect”, then choose “SSH client”, and copy and paste the example command into your terminal.

Note: If you had a "desired/minimum capacity" of 2 setting - like I do, then you will have to perform these on both instances running… 

Then install a stress tool with these commands:

sudo amazon-linux-extras install epel -y
sudo yum install stress -y

Then execute the stress test with this command as well:

sudo stress --cpu  6

Now go to your Instances page, and see if a third instance is added…

Note: this could take a few minutes...

It worked!

Now lets SSH into our private subnet from one of our public instances:

If you still have the stress test running, end the test (on a mac this is control “c”), and go into your private instance and select “connect” for SSH and copy and paste this into the command line while logged into your public instance.

It should look similar to this:

Thanks for following along with me on this journey! Don’t forget to end all the services, and release your elastic IP address!



Dane Forslund

DevOps | Cloud | AWS enthusiast. I believe my most successful moments have derived from patient leadership, proactive resolve, and often adversity.