Lesson 6 · 20 min read

VPC: Subnets, Route Tables, Security Groups

Your own private network inside AWS. Public and private subnets, how traffic gets in and out, and where your database hides.

What you'll learn in this lesson

  1. Concept: your own private network
  2. Why this matters
  3. The analogy — an office building
  4. IP ranges and CIDR, once and for all
  5. The seven pieces of a VPC
  6. What makes a subnet public or private
  7. Security Groups vs Network ACLs
  8. NAT Gateway — and why it can raise your bill
  9. The default VPC — and why we do not use it
  10. Build it: the full VPC, step by step
  11. When something cannot connect — the checklist
  12. What this costs
  13. Interview corner
  14. Practice task before Lesson 7
  15. Conclusion

Concept

A VPC (Virtual Private Cloud) is your own private network inside AWS. It is a part of AWS's huge data centres that belongs only to you. It has its own range of IP addresses, its own doors to the internet and its own firewalls. (An IP address is the number that identifies a computer on a network. A firewall is a filter that allows or blocks network traffic.) Nothing gets in or out unless you built a door for it.

In Lesson 2 you learned how a request travels across the internet to a server. A VPC is the network on the server's side of that journey. On Vercel this layer is hidden. On AWS you design it yourself.

A VPC costs nothing

The VPC, subnets, route tables, Internet Gateway and Security Groups are all free. You only pay for the things you put inside (servers, databases). You also pay for one optional piece, the NAT Gateway, which we cover carefully below.

Why this matters

Many serious AWS mistakes are networking mistakes:

  • A database is launched with a public IP and a Security Group that allows 0.0.0.0/0 (every address on the internet) on port 5432 (the PostgreSQL port). Within hours, bots try passwords against it. This is how many “company X leaked millions of records” stories begin.
  • A server “cannot be reached” for two days, because nobody knew that the route table was the problem and not the Security Group.
  • A NAT Gateway is left running for a month. It quietly costs more than the servers.

A well-designed VPC makes the safe choice the default. The database physically cannot be reached from the internet, because there is no path to it. This is much stronger than a firewall rule that you hope nobody edits.

Fresher or four years in — same idea

If you are new, use this lesson to learn the words you will see in every AWS diagram. If you have some experience, keep the main idea. A subnet is public only because of one route-table row. Security has two separate layers (the network shape and the firewall), and both should say no.

The analogy — an office building

Picture a company that rents a whole building.

In the buildingIn AWS
The building itself, with its own address blockVPC
Floors (some open to visitors, some staff-only)Subnets (public / private)
The main entrance on the streetInternet Gateway
Signs in the lift: “visitors → floor 1, finance → floor 3”Route tables
A guard at each office door checking a list of namesSecurity Groups
A guard at each floor's lift lobbyNetwork ACLs
A phone line staff can dial out on, but nobody can dial in onNAT Gateway

The reception desk and the shop front are on the public floor. The finance department and the safe are on a staff-only floor with no door to the street at all. This one design choice does most of the security work.

IP ranges and CIDR, once and for all

CIDR (Classless Inter-Domain Routing) is a short way to write a whole range of IP addresses, such as 10.0.0.0/16. You met it in Lesson 2. Now it is practical, because AWS asks you to choose a range when you create a VPC. The rule is short:

The only CIDR rule you need

An IPv4 address has 32 bits (32 on/off switches). In 10.0.0.0/16, the number after the slash says that the first 16 bits are fixed and the other 16 are free. The count of addresses is 2^(32 − prefix). So /16 = 65,536 addresses, /24 = 256, /28 = 16, and /32 = exactly one.

CIDRAddressesTypical use
10.0.0.0/1665,536The whole VPC (the largest AWS allows is /16)
10.0.1.0/24256 (251 usable)One subnet
10.0.1.0/2816 (11 usable)The smallest AWS subnet
203.0.113.7/321“Only my office IP” in a Security Group

Why 251 and not 256? AWS keeps five addresses in every subnet for its own use: the network address, the VPC router, the DNS server, one saved for future use, and the broadcast address. (The router passes traffic between networks. DNS turns names into IP addresses. A broadcast address sends a message to every device at once.) This is a favourite interview question.

Choosing the range — three practical rules

  • Use a private range: 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16. These ranges are reserved for private networks and are never used on the public internet.
  • Do not overlap with any network you may connect later, such as your office, a second VPC or a partner. Two networks with the same range cannot be joined. This is hard to fix afterwards, so real teams plan the ranges on paper first.
  • Leave room to grow. A /16 VPC with /24 subnets costs nothing. It gives you room for 256 subnets of 251 usable addresses each.

The seven pieces of a VPC

PieceWhat it doesExample
VPCYour whole private network. It has one address range and lives inside one AWS region.10.0.0.0/16
SubnetA smaller slice of the VPC’s address range. It lives in exactly one Availability Zone.10.0.1.0/24 in ap-south-1a
Route tableA list of rules that say “traffic going to X, send it to Y”. Every subnet uses one.0.0.0.0/0 → igw-…
Internet Gateway (IGW)A VPC component that connects the VPC to the public internet, like a front door. Free. One per VPC.igw-0abc…
NAT GatewayA one-way door. Private servers can call out to the internet, but nobody can call in.nat-0abc… (paid)
Security GroupA firewall attached to a resource (server, database or load balancer). It lists which traffic is allowed.web-sg, db-sg
Network ACLA basic firewall attached to a whole subnet. You rarely edit it.default: allow all

Here is the layout this whole course builds. Read it top to bottom, like a request would.

Internet → Internet Gateway
VPC · 10.0.0.0/16 · ap-south-1
Public subnet · 10.0.1.0/24
route table: 0.0.0.0/0 → Internet Gateway
ALB — public IP
EC2 · Nginx + app — SG: 22 from you, 80/443 from ALB
Private subnet · 10.0.2.0/24
route table: no internet route (NAT only for updates)
RDS PostgreSQL :5432 — SG: only from the app's SG
Redis :6379 — SG: only from the app's SG
One VPC, two kinds of subnet. Public subnets have a route to the Internet Gateway; private subnets do not, so the database can only be reached from inside. · 10.0.0.0/16

Availability Zones — why we make four subnets, not two

A region is a geographic area where AWS runs data centres, such as ap-south-1 (Mumbai). Each region has several separate groups of data centres called Availability Zones (AZs), for example ap-south-1a, 1b and 1c. They are far enough apart that a fire or a power cut in one does not affect the others.

A subnet lives in one AZ. To survive the failure of an AZ, you need each kind of subnet in at least two AZs. Two services require this later:

  • The load balancer (Lesson 12) needs subnets in at least two AZs. A load balancer is a service that shares incoming requests between several servers.
  • An RDS subnet group (Lesson 8) needs subnets in at least two AZs, even if you run only one database. RDS is the AWS managed database service.

So we create four subnets: one public and one private in AZ a, and one public and one private in AZ b. This is cheap (subnets are free) and saves you a rebuild later.

What makes a subnet public or private

Many people misunderstand this idea in AWS networking, but it is simple.

The definition — memorise it

A subnet is public if its route table has a row 0.0.0.0/0 → Internet Gateway. A subnet is private if it does not. There is no “public” checkbox on the subnet itself.

A route table works like the signs in a lift. When traffic leaves, AWS looks for the row with the most specific matching range first. Here are two examples:

Route table of a PUBLIC subnet
Destination       Target
10.0.0.0/16       local          # anything inside the VPC stays inside
0.0.0.0/0         igw-0abc123    # everything else goes out the front door
Route table of a PRIVATE subnet
Destination       Target
10.0.0.0/16       local          # can talk to other subnets in this VPC
                                 # no 0.0.0.0/0 row = no path to the internet at all

The local row is added automatically and cannot be deleted. It is the reason an app server in a public subnet can reach a database in a private subnet with no extra setup. Inside the VPC, every subnet has a route to every other subnet. Security Groups, not routes, decide who is actually allowed in.

A public subnet is not enough — the public IP

For a server to be reachable from the internet, it needs both a public subnet and a public IP address. The public IP can be assigned automatically, or it can be an Elastic IP (a fixed public address, from Lesson 7). A server in a public subnet without a public IP can talk to other servers inside the VPC. It cannot reach the internet, and the internet cannot reach it. The reason is that the IGW only translates addresses for instances that have a public one. This is a common mistake. Remember: you need the route and the public IP.

Security Groups vs Network ACLs

You have used Security Groups since Lesson 2. AWS also gives you a second, older firewall called a Network ACL (NACL, where ACL means access control list). Here is how they differ. The question “explain SG vs NACL” is asked in almost every AWS interview.

Two words in the table need a plain explanation. Stateful means the firewall remembers a connection. If a request is allowed in, the reply is allowed out automatically. Stateless means the firewall remembers nothing, so you must write a rule for the reply traffic too.

Security GroupNetwork ACL
Attached toA resource (instance, database, load balancer)A whole subnet
Rule typesAllow onlyAllow and Deny
StateStateful — replies are allowed automaticallyStateless — you must allow the return traffic yourself
Rule evaluationAll rules togetherNumbered, lowest number first, first match wins
DefaultInbound: deny all. Outbound: allow allDefault NACL allows everything
You edit itConstantlyAlmost never

Our rule: leave the NACL at its default (allow all) and do your real work with Security Groups. Use a NACL only for one job that Security Groups cannot do: block a bad IP range for a whole subnet.

The best Security Group trick — reference another group

Instead of an IP address, a rule can name another Security Group as the source. This keeps the database private, even when you add more servers:

Security Groups we create in this lesson
alb-sg   inbound: 80, 443   from 0.0.0.0/0        # the public front door
web-sg   inbound: 80, 443   from alb-sg           # only the load balancer may talk to servers
         inbound: 22        from YOUR-IP/32       # only you may SSH
db-sg    inbound: 5432      from web-sg           # only app servers may reach Postgres
cache-sg inbound: 6379      from web-sg           # only app servers may reach Redis

Auto Scaling is the AWS feature that adds or removes servers when traffic changes. When it launches a tenth server, that server joins web-sg and may reach the database at once. There is no rule to edit and no IP to allow. A stranger who has the database password still cannot connect, because their machine is not in web-sg. Layer one (the private subnet) and layer two (the Security Group) both say no.

NAT Gateway — and why it can raise your bill

Here is a real problem. A server in the private subnet needs to download operating-system security updates. But it has no route to the internet. That was the whole point. How does it reach the update servers?

A NAT Gateway (NAT means Network Address Translation) is an AWS service that lets private servers start connections to the internet without being reachable from it. It sits in a public subnet. Private servers send their outbound traffic to it. It forwards the traffic using its own public IP and passes the replies back. Outsiders cannot start a connection to the private server. The door opens one way only, like a phone that can call out but has no number for people to call in.

The bill nobody warns you about

A NAT Gateway costs roughly $0.056 per hour (about $40 a month) plus $0.056 per GB it processes in Mumbai. The hourly charge applies even when it is idle. For a small project this can be double the cost of everything else together. Prices change, so check the current VPC pricing page.

Many beginners create one in the wizard, forget it, and find the cost a month later.

Ways to avoid paying for it

  • Our approach in this course: skip the NAT. The database never needs to call the internet, because AWS patches RDS for you. Only the app servers need outbound access. They live in the public subnet, where the Internet Gateway gives it to them for free.
  • VPC endpoints are private doors from your VPC to an AWS service. The Gateway type, for S3 and DynamoDB, is free. It lets private servers reach S3 without a NAT and without using the internet. Add one whenever a private server talks to S3.
  • Interface endpoints (for SSM, ECR, Secrets Manager and others) cost about $0.011 per hour per AZ. This can be cheaper than a NAT if you need only a few services.
  • Real production usually does use a NAT (one per AZ, so that one AZ failure does not cut off the others). If your traffic is high, it is worth it. At the size of this course, it is not.
Public IPv4 is not free either

Since February 2024, AWS charges about $0.005 per hour (roughly $3.60 a month) for every public IPv4 address. This includes the ones on your own servers and load balancers. It is small for one address, but it is a good reason not to give public IPs to things that do not need them.

The default VPC — and why we do not use it

Every region in a new AWS account already has a default VPC. It has a public subnet in every AZ and an Internet Gateway attached. This is why the “launch instance” wizard works for a beginner: it puts your server in the default VPC without telling you.

The default VPC is fine for learning EC2 in ten minutes. It is wrong for real work:

  • Every subnet is public, so there is nowhere safe to put a database.
  • Instances get public IPs by default.
  • You did not design it, so you do not know exactly what is in it.

You should know that it exists and that you can leave it alone. Do not delete it, because some services expect it. We build our own VPC.

Build it: the full VPC, step by step

The console builds most of this on one screen. Take your time and read each field. Every box matches one piece from the diagram above. In Lesson 15 you will write the same network as code with Terraform (a tool that creates cloud resources from text files).

  1. Create the VPC and its subnets

    VPC → Create VPC → choose VPC and more. Name it myapp, CIDR 10.0.0.0/16, 2 Availability Zones, 2 public and 2 private subnets, NAT gateways None (they cost money — see above), VPC endpoints None, and keep DNS hostnames enabled (RDS endpoint names need it).

    The preview on the right is the resource map. It shows four subnets, one Internet Gateway and route tables that are already connected. Create it.

  2. Read what the wizard made

    Open the public route table: it has the local row plus 0.0.0.0/0 → igw-…. That one row is the whole difference between public and private. The private route tables have only local. An Internet Gateway that no route points to does nothing. The route is the sign that sends traffic to the door.

    On each public subnet, turn on auto-assign public IPv4 (Edit subnet settings), so servers launched there get a public address.

  3. Create the three Security Groups

    EC2 → Security Groups → Create, in the myapp VPC:

    GroupInbound ruleSource
    alb-sgHTTP 80, HTTPS 4430.0.0.0/0 — the whole internet
    web-sgHTTP 80, HTTPS 443the group alb-sg
    web-sgSSH 22“My IP” (a /32)
    db-sgPostgreSQL 5432the group web-sg

    For the group-to-group rules, type sg- in the source box and pick the group by name. This is the trick from above: the rule follows the servers, not their IP addresses.

    Your IP changes

    Home and mobile connections often get a new IP address after some days. If SSH suddenly times out next week, update the “My IP” rule. SSH is the secure remote login tool, and it uses port 22. In Lesson 18 you will remove port 22 and use SSM Session Manager instead (an AWS tool that opens a shell without any open port).

  4. Write down the IDs

    Later lessons ask for “the private subnets” or “web-sg”. Keep a note of the VPC ID, the four subnet IDs and the three Security Group IDs. The console shows them all on the VPC's resource map.

When something cannot connect — the checklist

Sooner or later you will watch an ssh command hang or a browser spinner turn forever. Do not guess. Check the request's path in order. A packet is a small piece of data sent over the network, so follow the packet:

#QuestionWhere to look
1Is the instance running and did it pass both status checks?EC2 → Instances → Status check column
2Does it have a public IP (or Elastic IP)?A private-only instance can never be reached from the internet
3Does the Security Group allow this port from your IP?Inbound rules — most common cause, by far
4Does the subnet’s route table have 0.0.0.0/0 → igw?This is what makes a subnet public
5Does the Network ACL allow it in both directions?Default NACL allows everything; custom ones deny by default
6Is a program really listening on that port on the server?Run ss -tlnp on the server. A port with no program behind it is not a firewall problem
7Is the server’s own firewall (ufw) blocking it?Ubuntu AMIs have ufw turned off, but check with: sudo ufw status

Read the symptom, not just the failure

What you seeWhat it usually means
Connection timed out (hangs)Something is silently dropping the packets: a Security Group, a route table or a NACL. Nothing answered at all.
Connection refused (instant)The packet arrived, but no program is listening on that port. The network is fine. The app is not running, or it listens on the wrong address.
Permission denied (publickey)The network is fine. The key file is wrong, the username is wrong (use ubuntu on Ubuntu, not ec2-user), or the .pem file permissions are too open.
A useful tool: VPC Reachability Analyzer

In the console, go to VPC → Reachability Analyzer. Pick a source and a destination. AWS then tells you exactly which part (Security Group, route or NACL) blocks the path. It costs about $0.10 per analysis and can save hours.

What this costs

ItemCost in Mumbai (approx.)
VPC, subnets, route tables, Security Groups, NACLsFree
Internet GatewayFree (you pay for data leaving AWS)
Gateway endpoint for S3Free
Public IPv4 address, each~$0.005/hour (~$3.60/month)
NAT Gateway~$0.056/hour + ~$0.056/GB (~$40/month idle)
Interface endpoint, each per AZ~$0.011/hour (~$8/month)

Everything you built above is free. We are deliberately not creating a NAT Gateway in this course.

Interview corner

Read the question and try to answer out loud in two sentences. Then open the answer. These questions come up in real AWS interviews.

What makes a subnet public?

Its route table has a route for 0.0.0.0/0 that points to an Internet Gateway. The subnet has no “public” setting of its own. Instances in it also need a public IP or an Elastic IP to be reachable from the internet.

Security Group vs Network ACL?

Security Groups are stateful, attach to resources, and have only allow rules. NACLs are stateless, attach to subnets, have both allow and deny rules, and are checked in number order. In practice you manage Security Groups and leave NACLs at the default.

How can a private-subnet server download updates without being reachable from the internet?

Through a NAT Gateway in a public subnet. Outbound connections go out and the replies come back, but nobody outside can start a connection in. For S3 only, a free Gateway VPC endpoint avoids the NAT completely.

Why does a subnet have only 251 usable addresses in a /24?

AWS keeps five addresses in each subnet: the network address, the VPC router, DNS, one for future use, and the broadcast address.

Your app in a public subnet cannot reach the internet, though the route to the IGW exists. Why?

The instance has no public IP or Elastic IP. The Internet Gateway only translates addresses for instances that have one. Also check the outbound Security Group rules and the NACL.

Design a VPC for a web app with a database. What goes where?

One VPC, two AZs, and a public and a private subnet in each. Put the load balancer in the public subnets. Put the app servers in public subnets (cheap) or private subnets (stricter, but they need a NAT or endpoints). Put the database and cache in private subnets, with Security Groups that accept traffic only from the app's Security Group.

Two VPCs need to talk to each other. What are the options and the catch?

VPC peering is a direct link between two VPCs. It is simple, but it is not transitive (if A peers with B and B peers with C, A still cannot reach C). Transit Gateway is a central hub that connects many VPCs, and it costs more. The catch for both: the CIDR ranges must not overlap.


Practice task before Lesson 7

Build the network from the previous section. Then check that it works as designed. Everything is free.

  1. Confirm four subnets, one Internet Gateway, one custom route table and three Security Groups exist in the console (VPC → Your VPCs → the resource map shows the picture).
  2. Open the resource map and find the line from the public route table to the IGW. Now delete that one route in the console. What do you predict happens to the public subnets? Add it back.
  3. Draw the VPC on paper without looking. Label each subnet with its CIDR, its AZ and whether it is public. Compare your drawing with the figure above.
  4. Write down, for each Security Group, who may connect on which port. Which of the three has a rule that names another group instead of an IP, and why is that better?
  5. Stretch: create a free S3 Gateway endpoint (VPC → Endpoints → Create → S3, type Gateway, pick your route tables). It adds a route to the table. Find it.
Cleaning up

Nothing here costs money, so keep it all. Lessons 7 and 8 launch resources into these subnets. If you ever need to delete, work in reverse order: instances first, then Security Groups (not the default one), then detach and delete the IGW, then the subnets and route tables, and last the VPC.

Conclusion

A VPC is a private building you rent inside AWS. Subnets are its floors. Route tables are the signs that decide where traffic goes. The Internet Gateway is the front door. Security Groups are the guards at each office.

  • Public vs private is one route-table row: 0.0.0.0/0 → igw. Delete it and the subnet is private.
  • Two layers of safety: the database is in a private subnet and its Security Group accepts only the app's Security Group.
  • Two AZs from day one, because the load balancer and RDS both demand it.
  • NAT Gateways cost money and are easy to forget. Skip them until your traffic needs them. Use free S3 endpoints instead.
  • Debug in path order: instance → public IP → Security Group → route → NACL → listening port. “Timed out” means something blocked the traffic. “Refused” means no program was listening.

The network exists, but it is empty. Next we put the first real server in it: EC2.


End of Lesson 6. Next: Lesson 7 — EC2: Launch Your First Server and Deploy Next.js Manually.

Published by Jainik · Last updated · How these lessons are made

Keep learning

Part of the study guide

Related series