Start free
← All guides

Learn

VPC, subnets, route tables and security groups — how AWS networking fits together

The five objects that decide whether your traffic arrives: VPCs, subnets, route tables, internet and NAT gateways, and security groups. What each does, and the specific reasons a connection hangs instead of failing.

Updated 2026-08-02

AWS networking has a reputation for being impenetrable, but it is five objects with clear jobs. The difficulty is that when you get one wrong, nothing tells you which one — the request simply hangs until it times out.

The five objects

ObjectJobScope
VPCA private network with an address rangeRegion
SubnetA slice of that range, in one availability zoneOne AZ
Route tableWhere traffic leaving a subnet goesAttached to subnets
GatewayThe door out (internet, or NAT)VPC
Security groupPer-resource firewallAttached to resources

VPC: the address space

A VPC is a private network you own, defined by a CIDR block such as 10.0.0.0/16 — about 65,000 addresses. Nothing inside it is reachable from the internet unless you deliberately build a path.

Pick a range and leave room. 10.0.0.0/16 is conventional because it subdivides cleanly and does not collide with the 192.168.x.x your office router probably uses. Overlapping ranges become a genuine problem the day you peer two VPCs or connect a VPN, and the fix at that point is a migration.

Subnets: slices tied to one availability zone

A subnet is a piece of the VPC range that lives in exactly one availability zone. That AZ binding is the reason subnets exist: to be resilient you place resources in at least two AZs, which means at least two subnets.

The words public and private are not settings. They describe one thing only: whether the subnet's route table has a route to an internet gateway.

10.0.0.0/16         VPC
├── 10.0.1.0/24     public subnet,  us-east-1a  → route to IGW
├── 10.0.2.0/24     public subnet,  us-east-1b  → route to IGW
├── 10.0.10.0/24    private subnet, us-east-1a  → route to NAT
└── 10.0.11.0/24    private subnet, us-east-1b  → route to NAT

AWS reserves five addresses in every subnet — the first four and the last — so a /24 gives you 251 usable, not 256.

Route tables: the actual decision

A route table is a list of destinations and targets. Every subnet has one, and it is what genuinely determines public versus private.

A public subnet's table:

10.0.0.0/16   →  local            (traffic within the VPC)
0.0.0.0/0     →  igw-0abc123      (everything else → internet gateway)

A private subnet's table:

10.0.0.0/16   →  local
0.0.0.0/0     →  nat-0def456      (everything else → NAT gateway)

The local route is created automatically and cannot be removed: everything in a VPC can route to everything else in that VPC, always. Whether it is allowed is a security group question, not a routing one.

Gateways: internet and NAT

An internet gateway attaches to the VPC and permits two-way traffic. A resource still needs a public IP and a route to it before anything reaches it.

A NAT gateway allows outbound-only traffic. Instances in private subnets can reach the internet to fetch packages or call APIs, but nothing on the internet can open a connection to them. It lives in a public subnet and forwards on their behalf.

NAT gateways cost money — an hourly charge plus per-GB processing — and are a common surprise on a first bill. A private subnet with no NAT is free but has no outbound internet at all, which is correct for many databases.

Security groups: stateful, per-resource, allow-only

A security group is a firewall attached to a resource rather than a subnet. Three properties explain nearly all of its behaviour:

Allow-only. You cannot write a deny rule. Anything not explicitly allowed is denied, so security groups only ever add permission.

Stateful. Allow traffic in and the reply is automatically permitted out. You do not write return rules — a persistent source of confusion for anyone arriving from traditional firewalls.

They can reference each other. This is the feature worth learning. Instead of allowing a CIDR range, allow another security group:

Allow TCP 5432 from sg-app     (not from 10.0.10.0/24)

Now every instance in the app group can reach the database, forever, regardless of how many are added, what addresses they get, or how often they are replaced. Rules written against IP ranges rot; rules written against groups do not. When Korve wires ec2 → rds, this is exactly the rule it creates — group-to-group, on the port the database is actually listening on.

Network ACLs, and why you probably should not touch them

NACLs are the other firewall: attached to subnets, stateless, and they support deny rules.

Stateless means return traffic needs its own explicit rule, on the ephemeral port range (1024–65535), in the opposite direction. Forget that and you get connections that establish and then hang — the request arrives, the reply is dropped.

The default NACL allows everything, delegating the decision to security groups. For most architectures that is the right arrangement. Reach for NACLs when you need an explicit deny — blocking a specific address range — which security groups cannot express.

Why your connection hangs

Almost every AWS networking failure is one of these, in roughly this order of likelihood:

A useful diagnostic: a connection refused means you reached something and it said no — routing works, the service is not listening. A connection that hangs means packets are disappearing — routing or a firewall. Refused is a much better error, because it tells you the network is fine.

What this looks like on a canvas

The reason this is hard on the console is that the objects are spread across separate screens with no picture of how they relate. A VPC page, a subnet page, a route table page, a security group page — and the relationships between them exist only in your head.

Drawing it makes the shape obvious: which subnet a resource is in, which VPC that subnet belongs to, and which connections cross between them. Wiring vpc → subnet records that membership explicitly, and the security group rules that make traffic actually flow are created from the connections you draw rather than assembled by hand across four screens.

Build this on a canvas instead of the console.

Start Korve free →