Skip to main content

Building an AWS VPC from Scratch

Hands-On Lab


Photo of joel


Training Architect





Welcome to this hands-on AWS Learning Activity, Building a Basic VPC. This activity provides you with some experience building and connecting the following services inside AWS: - VPC - Subnets - Internet Gateway - Route Tables - Security Groups - Network Access Control Lists (NACLs) These services are the foundation of networking architecture inside of AWS, and cover concepts such as infrastructure, design, routing, and security. Good luck, and enjoy this learning activity!

What are Hands-On Labs?

Hands-On Labs are scenario-based learning environments where learners can practice without consequences. Don't compromise a system or waste money on expensive downloads. Practice real-world skills without the real-world risk, no assembly required.

Building an AWS VPC from Scratch


Welcome to this hands-on AWS lab, where we'll be building a basic VPC (Virtual Private Cloud), which is the basic network framework in AWS. There are several other essential features that we'll need as well, once we've configured a VPC, in order to get started with network in an AWS environment.

Here's a rundown of what we'll be doing:

  • Create a VPC
  • Create an internet gateway
  • Create subnets
    • Two public, where things like web servers or Application Load Balancers might live
    • Two private, where things like mail or database servers would reside
  • Create route tables
    • One private, and one public, to route traffic appropriately to the subnets
  • Set up firewall rules
    • Stateful and stateless (one each) using subnet groups and network access control lists, or ACLs (respectively)

With all that in mind, let's get right to it.

Log In

Use the credentials provided in the lab to log in to the AWS console. Our username will be cloud_user, with an autogenerated password.

Once we're in, make sure we're using the us-east-1 (N. Virginia) region.

Create a VPC

Navigate to Services, then click VPC in the Networking & Content Delivery section.

Here, we'll see a Start VPC Wizard button. If we click that, then many of the VPC's features would be configured for us. The point of this lab, though, is to get familiar with all of these options, so we're doing everything manually. Instead of Start VPC Wizard, click Your VPCs in the left-hand menu.

Now we can click Create VPC up at the top. A dialog will pop up. Enter Lab_VPC in the Name tag field, and in the IPv4 CIDR block field. We can leave the IPv6 CIDR block selection at No IPv6 CIDR Block, since we don't need any IPv6 addresses here. We can also leave Tenancy set to Default. Click Create when everything looks good, and close out so that we land back at the VPC Dashboard.

Now we're back at the Your VPC page, and we can see our Lab_VPC was created with all the options we set in the pop-out dialog. Note the VPC ID column. That column for our newly created VPC will say something like vpc-xxxxxxxx.

Create an Internet Gateway

Click in the left menu on Internet Gateways, and click Create internet gateway near the top of the screen.

All we need is something in the Name tag field, so let's enter lab_igw (short for "lab internet gateway") and click Create over on the right. When it's created successfully, it's safe to hit Close on the right.

Back in the Internet Gateway screen, we can see that the gateway was created, but that it has a state of detached. Make sure the box is selected (the left-most column), then choose Attach to VPC from the Actions menu up near the top of the screen. Select Attach to VPC from that menu, and we'll be taken to another screen with a dropdown. Select the one that just got created (that VPC ID from the last step, vpc-xxxxxxxx), and click Attach.

As things sit currently, we've got a VPC:

  • It resides in the us-east-1 region.
  • It has a CIDR block of

We have also created an internet gateway we attached to our new VPC.

We're good to go here. Let's move on to subnets and route tables.

Create Subnets

We're going to set up four subnets: two public and two private. And we'll set one each (a public one and a private one) in each of the two availability zones.

Create First Public Subnet

First off, navigate to Subnets (a link in the left-hand menu), and we'll see we've got nothing set up here. Click Create Subnet to make one.

For a Name tag, we can call it whatever we want. To stick with our current naming convention, though, and maybe just keep things simpler, we'll use Subnet-1-Public. The VPC should have autopopulated, but choose vpc-xxxxxxxx | Lab_VPC from the dropdown if it didn't.

Set us-east-1a as an Availability Zone, and set the IPv4 CIDR block to Click Create, then Close to get back into the Subnets screen. Create the remaining public and private subnets with these specifications:

Create Second Public Subnet

  • Name tag: Subnet-2-Public
  • Same VPC
  • Availability Zone: us-east-1b
  • IPv4 CIDR block:

Create First Private Subnet

  • Name tag: Subnet-3-Private
  • Same VPC
  • Availability Zone: us-east-1a
  • IPv4 CIDR block:

Create Second Private Subnet

  • Name tag: Subnet-4-Private
  • Same VPC
  • Availability Zone: us-east-1b
  • IPv4 CIDR block:

Note the names of all four subnets once we're done creating them. The words Public and Private are in the names themselves, but have no bearing on whether they are in fact public or private subnets. What does determine this is whether or not the subnets can talk to the outside world, and we'll set this up with route tables.

Create Route Tables

We'll be setting up two route tables: a private and a public. The public route table will have a connection to our gateway that will allow any instances we deploy in those subnets to communicate with the outside world. Let's get this process moving by clicking on Route Tables in the left-hand VPC Dashboard menu.

We'll see right off there's already a default route table. All VPCs have these, and it's best to leave them alone. If we need to customize something, we're better off creating a new one. So let's click Create Route Table. In the Create Route Table screen, we'll use Public-RouteTable as a Name tag, ensure the VPC dropdown is set to our new vpc-xxxxxxxx | Lab_VPC, click Create, and then Close.

Now, we've got to create the private route table. We'll again click Create Route Table, use Private-RouteTable as a Name tag this time, make sure we've got vpc-xxxxxxxx | Lab_VPC set in the VPC dropdown, hit Create, and then Close.

Associate Route Tables

The Public Route Table

We're not quite done with the Public-RouteTable yet. We've got to create an additional route, besides the route to local. Make sure the box is checked next to Public-RouteTable (and only the box in the Public-RouteTable row) in our list of route tables. On the bottom of the dashboard screen, click the Routes tab, then Edit routes, and then Add route near the bottom.

First, select Internet Gateway in the Target column, and we should see our igw-xxxxxxxx show up in a list. As a Destination, we'll enter, which essentially means any destination. This rule, once we click Save routes, will route any traffic through the public route table and out onto the internet. Close this out to get back to our Route Tables screen.

Next, we've got to associate this route table with the proper subnets. Down near the bottom of the dashboard window, we can click the Subnet Associations tab and see all our subnets listed below. If we click Edit subnet associations, we can associate the route table to Subnet-1-Public and Subnet-2-Public by checking the boxes to the left of each in the Associate column.

Once we click Save, we can see back in the console that the Explicitly Associated column now shows 2 Subnets for our Public-RouteTable.

The Private Route Table

We weren't done with the Private-RouteTable yet either. Let's make sure the checkbox next to it is selected, and that it is the only checked checkbox.

We can leave the Route tab alone, because this route table will only be routing locally. But in the Subnet Associations tab, click the Edit subnet associations button, and associate this route table with the two private subnets by checking the boxes next to them. Once we click Save, we're done with this part of the exercise.

Make a note, though, about something that might be handy to remember down the road: A subnet can only be associated with one route table at a time. Route tables can be associated with multiple subnets, as we just illustrated, but the reverse isn't true.

Secure the VPC

We're going to look at two ways to secure this VPC: One is a stateful firewall, or a security group, and the other is stateless, using ACLs. Let's get the two terms — stateless and stateful — defined a little better, though, before we dig in.

  • Stateful firewall: This is "aware" of connections being made to it. Once an inbound or outbound connection is made, a stateful firewall will automatically allow traffic to flow in the opposite direction. So, on a web server, imagine a stateful firewall with a rule allowing incoming traffic on port 80. Traffic will also be allowed out on port 80 to that original source without needing an outbound rule.
  • Stateless firewall: That same web server, if it was employing a stateless firewall, would need two rules: One rule would allow traffic on port 80 in from a source, and the other rule would allow traffic back out to that source on port 80.

To get the ball rolling, let's click Security Groups, out in the main VPC Dashboard (in the left-hand menu). We can see there's a default security group sitting there already. We'll leave that alone and create a new one.

The Stateful Firewall

If we click Create Security Group, we'll land on a screen with some fields we need to fill in. In the Name tag field, call it Lab_SG. That will work in the Description field too. In the dropdown, right below, make sure the correct VPC is selected (vpc-xxxxxxxx | Lab_VPC), and click Create. Close out, and we'll land back at the Security Groups screen.

Check our new one (and make sure the other default one isn't checked), and click the Inbound Rules tab down in the lower portion of the screen. There aren't currently any rules, so no traffic is allowed. Click Edit rules to set up a rule.

Click Add Rule, and in this next screen we've got a bit of work to do. Under Type, select HTTP. The Protocol column defaults to TCP, which we can leave alone. We'll also see the Port Range column gets set to 80 automatically. The Source column should automatically be set to, ::/0, which is fine. This means, essentially, any source. Give it a Description of Web Traffic, then click the blue Save rules button, and close out. We'll see the new rule was created, which will allow inbound traffic on port 80 from anywhere.

Since this is a stateful firewall, we don't have to create a rule in the Outbound Rules tab.

The Stateless Firewall

In the left-hand menu, click Network ACLs in the Security section. Once we're there, we'll find a default network ACL, just like we already had a default security group before we even started working on the stateful firewall. And just like we did over there, we're going to leave this default one alone. Click Create Network ACL to get things moving.

In the next screen, enter Lab_NACL as a Name tag, and make sure our vpc-xxxxxxxx | Lab_VPC is selected in the VPC dropdown. Once we click Create and get dumped back out to the Network ACL screen, we can start setting up some rules. Make sure our new network ACL is what's checked and that the default one is unchecked.

Down in the lower part of the screen, get into the Inbound Rules tab. Click Edit inbound rules, and then Add Rule. We'll give it a Rule # (this is also a priority) of 100, and a Type of HTTP (80). A Protocol of TCP (6) should already be set, and a Port Range of 80 was set when we selected our Type. We're going to set a Source of, which is essentially anywhere, and make sure Allow/Deny is set to ALLOW. Hit Save.

Notice, down near the bottom of the screen where our new rule is, there's a rule with a NULL priority, set to DENY any traffic coming from anywhere (the three column entries set to ALL). This is an implicit DENY, meaning all traffic is blocked from accessing subnets behind this network ACL list, unless there's a rule (like the one we just made) allowing it.

Because this is a stateless firewall, we can't just have an inbound rule. We have to make an outbound one too. In the Outbound Rules tab, add a rule just like we did in the Inbound Rules tab:

  • Rule #: 100
  • Type: HTTP (80)
  • Protocol: TCP (6) (which should have already been set)
  • Port Range: 80 (also already set when we selected our Type)
  • Source:
  • Allow/Deny: ALLOW

With our rules in place on the Network ACLs, let's attach some subnets to them. In the Subnet Associations tab, click Edit subnet associations. On this next screen, we can see all four (two public and two private) subnets we created earlier. Since this is a rule allowing web traffic to the public subnets, select both in the list and click Edit.


Now the public subnets will allow traffic (on port 80) in and out from any source to any destination. Anything else will be blocked. We've got the infrastructure laid out so someone can come in and start configuring something like EC2 instances as web servers and Application Load Balancers. Congratulations!