What’s the Difference Between a Public and Private Subnet in an AWS VPC?

AWS Public vs Private Subnet

This is a brief intro to quite a few of the AWS VPC components and how they fit together with the goal of describing the difference between a public and private subnet.

Amazon has this line in some VPC docs that hints at the difference:

The instances in the public subnet can send outbound traffic directly to the Internet, whereas the instances in the private subnet can’t.

Then buried in the details of those same docs is the real difference between a public and private subnet: the route table.

A public subnet has an outbound route that sends all traffic through what AWS calls an Internet Gateway (IGW). The IGW lets traffic — IPv4 or IPv6 — out of the VPC without any constraints on bandwidth. Instances in public subnets can also receive inbound traffic through the IGW as long as their security groups and Network ACLs allow it.

Contrast that with a private subnet which, if it needs to talk to the internet, must do so through a Network Address Translation (NAT) gateway. NATs are really common. Run a wireless router? The router itself does network address translation. Importantly a NAT won’t allow inbound traffic from the internet — that’s what makes a private subnet, well, private.

AWS has its own managed NAT Gateway offering for outbound IPv4 traffic and an egress-only IGW for IPv6 traffic.

The difference between a public and private subnet? A public subnet has a route table that says, “send all outbound traffic (anything to the CIDR block 0.0.0.0/0) via this internet gateway.” A private subnet either does not allow outbound traffic to the internet or has a route that says, “send all outbound traffic via this NAT gateway.”

It’s important to note that all subnets in a VPC can talk to one another as long as the host’s security groups allow it. There’s always a route that says “keep traffic to {YourVPCsCIDRblock} inside the VPC.”

Looking for an example of how one might set all this up? Check out this Terraform module.