2026-07-02 · 9 min read
AWS VPC Networking Explained for DevOps Engineers
A clear, practical mental model of AWS VPC networking, subnets, route tables, gateways, NAT, security groups vs NACLs, and VPC endpoints, without the jargon overload.

AWS VPC Networking Explained for DevOps Engineers
VPC networking is where a lot of DevOps engineers get stuck, not because it's hard, but because the pieces are introduced out of order. Here's the mental model that makes it click, built up one layer at a time.
The VPC is a private network in the cloud
A VPC is your own isolated network in an AWS region, defined by a CIDR block like
10.0.0.0/16 (65,536 addresses). Everything else lives inside it.
Subnets carve the VPC into zones
A subnet is a slice of the VPC's CIDR (e.g. 10.0.1.0/24) that lives in one Availability
Zone. Two rules of thumb:
- Public subnet: has a route to an Internet Gateway. Things here can have public IPs.
- Private subnet: no direct route to the internet. Databases and app servers belong here.
For high availability, you put subnets in at least two AZs.
Route tables decide where traffic goes
Each subnet is associated with a route table: a list of "for this destination, send to this target." The single most important distinction:
- A subnet whose route table sends
0.0.0.0/0to an Internet Gateway is public. - A subnet without that route is private.
That route is literally what makes a subnet public or private.
Gateways: how traffic enters and leaves
- Internet Gateway (IGW): lets public-subnet resources talk to the internet (in and out).
- NAT Gateway: lets private-subnet resources reach out to the internet (e.g. to download
updates) without being reachable from it. It lives in a public subnet; private route tables send
0.0.0.0/0to it. - VPN / Direct Connect / Transit Gateway: connect your VPC to on-prem or other VPCs.
Cost tip: NAT Gateways bill per hour and per GB. For purely AWS-bound traffic, VPC endpoints (below) avoid NAT entirely.
Security groups vs NACLs
Both filter traffic, but they work differently, and this trips everyone up:
| Security Group | Network ACL | |
|---|---|---|
| Attached to | ENI / instance | subnet |
| State | stateful (return traffic auto-allowed) | stateless (must allow both directions) |
| Rules | allow only | allow + deny |
| Default | deny all inbound, allow all outbound | allow all |
Use security groups as your primary control (stateful is far easier to reason about). Reach for NACLs only for coarse subnet-level deny rules.
VPC endpoints: reach AWS services privately
By default, calling S3 or DynamoDB from a private subnet goes out through the NAT Gateway to the public AWS endpoint, costing money and leaving your VPC. VPC endpoints keep that traffic on the AWS private network:
- Gateway endpoints (S3, DynamoDB): free, added as a route.
- Interface endpoints (most other services): an ENI in your subnet (small hourly cost, still cheaper and more secure than NAT for heavy AWS traffic).
A standard, sane layout
VPC 10.0.0.0/16
├── Public subnets (AZ-a, AZ-b) → IGW → ALB, NAT Gateways
└── Private subnets (AZ-a, AZ-b) → NAT → app servers, EKS nodes, RDS
→ VPC endpoints → S3 / DynamoDB privately
- Public subnets hold only what must be internet-facing (load balancers, NAT).
- Everything with data or compute lives private.
- Two AZs minimum for HA.
This is exactly the pattern in my terraform-aws-reference-architecture and gcp-landing-zone-terraform (GCP's equivalent), codified so you don't rebuild it by hand each time.
The mental shortcut
When something can't connect, ask in this order:
- Route table: is there a route to where I'm trying to go?
- Security group: does it allow this traffic (and is the SG stateful behaviour what I expect)?
- NACL: is a subnet-level deny blocking it?
- Public IP / NAT: does this resource have a path to the internet at all?
Nine times out of ten, it's the route table or the security group.
Designing or untangling AWS networking? That's part of my cloud consulting, get in touch.