Public and private are traffic outcomes created by paths, addresses, policy, and services.
I used to read VPC diagrams as if the labels did the work.
Public subnet. Private subnet. Public route table. Private route table.
The labels are helpful for people. AWS does not route traffic because a box has a reassuring name.
A subnet becomes public in the useful sense when its associated route table provides a path to an Internet Gateway. But that is only one condition in a longer chain. An EC2 instance that should be reached from the internet also needs a public IPv4 address or Elastic IP, policy that allows the requested traffic, and a service that is actually listening.
This became much clearer when I built a VPC manually instead of relying only on the wizard.
The VPC itself is the network boundary. Subnets divide its address range into smaller sections. Route tables tell traffic where to go next. The Internet Gateway provides a path between the VPC and the internet. Security groups and network ACLs filter traffic at different layers. The workload still has to answer the request when traffic reaches it.
None of those parts can be skipped by calling a subnet public.
A common failure is the route-table association. A new subnet uses the VPC main route table until you explicitly associate it with another table. You can create a beautiful route table with a default route to an Internet Gateway and still have an unreachable instance if the subnet is using a different table.
That detail changed how I read every VPC screen. I stopped asking, "Does this route table look right?" I started asking, "Which route table does this subnet actually use?"
Private does not mean disconnected. It means the workload does not accept direct internet-initiated traffic through a public address. A private EC2 instance can still initiate package downloads or outbound API calls through a NAT Gateway.
The NAT boundary is where many diagrams become misleading.
A public NAT Gateway sits in a public subnet and has a route through the Internet Gateway. The private subnet sends its default internet-bound traffic to that NAT Gateway. The NAT handles return traffic for connections initiated from inside.
That gives you a path like this:
Private EC2. Private route table. NAT Gateway in a public subnet. Public route table. Internet Gateway. Internet.
The private EC2 instance does not become public because it can download updates. NAT is not a public front door. It is not a bastion host. It does not give the private instance a public identity that accepts unsolicited inbound SSH.
This is why I think "public versus private" is a poor place to stop learning. The stronger mental model is reachability.
For every request, name the source, destination, protocol, next hop, address type, policy layer, and listener. A browser reaching an Apache instance is a different flow from a private instance reaching a package repository. One is inbound and depends on public addressing, route, policy, and a listener. The other is outbound and can travel through NAT without creating direct inbound exposure.
That distinction matters beyond certification questions. It is how you avoid building a network that is accidentally reachable, or assuming a private workload is broken because it cannot be reached the way a public test server can.
The next time a VPC diagram looks simple, trace one packet. Do not read the labels. Follow the path.
Try this in a sandbox
Draw a two-subnet VPC on paper. For one browser-to-web-server request and one private-instance-to-package-repository request, write the route table, next hop, address requirement, policy rule, and final service evidence each flow needs.
Continue the sequence
Start by tracing one request or one security claim end to end. The goal is not to collect more AWS screens. It is to learn what each one can prove before you change the system.


