Amazon Web Services is an incredibly complex environment. Most of its features no one will ever use, and accomplishing what you assume to be trivial tasks can take a considerable amount of time and energy before anything works (or you give up). The AWS veterans I know complain about VPCs constantly, and rightfully so. Setting up a VPC properly involves a lot of steps and it's nearly impossible to do anything without the knowledge of all the components and how they interact. I am of the opinion VPCs are woefully over-designed and doubt that much of the functionality is of much use to anyone that is using the Cloud. If you need that much control over your network, you likely have the means, and would be better off, to throw a bunch of Cisco gear in a rack somewhere.

This guide aims to illustrate how to get a working VPC up and ready for deployment as fast as possible. None of it is particularly difficult, it is more just a lot of small things that need to be clicked, checked, or attached.

For demonstration purposes, we will be assuming this VPC will hold a web application deployed via Opsworks. The majority of the steps here will work for nearly any deployment, however.

Note: we will not be covering NAT here. This guide assumes all your servers will get public IPs and you will allow public SSH to them. NAT introduces yet another level of complexity and is out-of-scope for this document.

0. Exploring VPCs

Before we go off clicking buttons, we should first understand everything that makes up a VPC, why we need each bit, and how each thing relates to the rest of the system.

  • VPC - The obvious first concept is that of the VPC. A VPC, or "Virtual Private Cloud", is Amazon's word for what is essentially a container around a network. A VPC is the highest-level and is an umbrella around all other resources.
  • Subnet - A subnet is essentially a DHCP server for a chunk of your VPCs IP range. Instances must go in a subnet, and are assigned internal IP addresses from it.
  • Security Group - These can be thought of kind of like firewalls. Instances in one security group cannot talk to instances in another security group unless explicitly allowed. Security groups also limit external traffic very similarly to a traditional firewall in that you have to allow certain ports to receive traffic. If you've ever been unable to ping or ssh into your VPC'ed servers, it was likely a problem with the security group.
  • Route Table - Each VPC gets a route table that defines how to route traffic. Basically exactly the same as regular routing on real networks.
  • Internet Gateway - The magic connection to the internet that for some reason has to be added manually. Adding one of these to the VPC allows connections to the outside world.

That should hopefully be enough so that we can get clicking.

1. Setting up the VPC

First off we need to create the VPC itself. Head to the VPC section of the AWS Console and click "Create VPC".


I've chosen the name my-vpc and the CIDR block of These both are fairly arbitrary and can be nearly anything you want. Depending on how many machines you plan to launch into your VPC, your CIDR block should reflect that. If you're not planning on having 200+ machines per subnet, then assigning a /24 block for the whole VPC is totally reasonable.

A keen eye will find that when creating a VPC, you are also given a DHCP Options Set, Route Table, and Network ACL by default.

vpc free stuff

Other than the Route Table, you can ignore these, for the most part.

2. Getting to the Internet

A small detail most people miss, and one that is non-obvious later on, is a VPC has no internet access by default. If you launch an Opsworks Instance into a VPC without an internet connection, it will hang on boot for a very long time until it eventually fails.

So let's add an Internet Gateway.

Click on "Internet Gateways" in the sidebar, and create one. I usually name mine the same as the VPC it's going to be attached to.

create igw

Once created, select it and click "Attach to VPC". Then select your VPC from the dropdown.

attach igw

But wait, there's more! We still haven't told anything to use the IGW, we've just told it to associate itself with a VPC.

Head to the "Route Tables" section via the sidebar and select the route table for your new VPC. A pane will open at the bottom of the screen; navigate to the "Routes" tab and add a route for that points to the new IGW (the target field should auto-complete when you focus it).

add igw route

Congratulations, you just saved yourself hours of painful debugging later.

3. Subnets

Probably the most important part of the VPC is the subnet. A subnet is essentially the same as its physical-network counterpart. Each subnet gets a slice of the VPC's CIDR block, and resources launched in the subnet will be assigned an IP in that range via DHCP automatically.

Since we allocated one Class-C block for our VPC, we're going to use /26 blocks for our subnets, which is ¼ of a Class-C. Each quarter will give us 64 addresses (59 usable because AWS reserves a few), which should be plenty, even for large-scale deployments.

Following with the web application deployment scenario, we'll need a database subnet and a subnet for our web servers. RDS requires us to have at least two subnets for database instances, spread across at least two availability zones

Our network will end up looking something like this:

  • web01:, us-east-1b
  • database01:, us-east-1b
  • database02:, us-east-1c

subnets created omg

For the web01 subnet, select it and under the actions dropdown select "Modify Public IP" and check the checkbox. We will want public IP addresses on all of our web servers, since we're not setting up any NAT stuff.

4. Security Groups

Finally, the last VPC component we need to configure is Security Groups. Security Groups act as a sort of firewall, filtering which ports and which types of traffic are allowed to pass through from the Scary Internet™ to the VPC.

When creating a VPC, we get a default security group aptly named default. We are now faced with a decision: how much do we really care? Since the goal of this document is to get a VPC set up as fast as possible and with as little friction as possible, setting up a set of custom security groups is not going to get us to our goal any sooner, and provides only minimal benefit to us at the moment. Launching everything in the default security group is totally fine if you don't care about limiting inter-machine communication. For critical production setups, I would recommend looking into security groups as an extra level of security between your various layers of services, but for now default will serve us just fine.

With that out of the way…

Select the default security group for your VPC, and navigate to the "Inbound Rules" tab. You can see the one default rule allows all traffic between machines within the security group. We need to poke a couple holes for the services we want to be able to access publicly.

Following with the Opsworks theme, I'm going to open up ports for HTTP and SSH from any IP address.

opening http and ssh

The "Source" fields will attempt to auto-complete names of security groups in your VPC. Since we're entering an IP range, it will complain about "No results" -- you can ignore these complaints.

Coffee break

You've now set up a VPC worthy of being used. Now you can start launching RDS instances, setting up Opsworks apps, perhaps even exploring security groups more and learning how to lock down your internal traffic. Perhaps you're feeling inspired and want to take it a step further with NAT instances and private LANs...