DEV Community

Cover image for AWS VPC: Public & Private Subnets with EC2 & Docker
Rajesh
Rajesh

Posted on

AWS VPC: Public & Private Subnets with EC2 & Docker

Why do we need a custom VPC & Subnets?

Without network isolation, every server you launch sits on a shared network accessible to anyone on the internet.

A Virtual Private Cloud (VPC) gives you your own isolated private data center in the cloud. You decide which servers face the public internet and which backend databases stay completely shielded inside private subnets where no outsider can touch them.


1. The VPC (Virtual Private Cloud) & CIDR Planning

Think of a VPC as a private gated apartment complex inside the giant AWS city. You decide the boundary walls, the internal road layout, and who gets through the gate.

  • Region Scope: A VPC lives inside one AWS Region and spans across all Availability Zones in that Region.
  • CIDR Block: You assign your VPC an IPv4 range (between /16 with 65,536 IPs down to /28 with 16 IPs) using private IP standards (like 10.0.0.0/16).
  • CIDR Math in Plain English: The number after the slash tells you how many network bits are locked. A smaller number means a bigger network:
    • /16 = 65,536 addresses (standard for a company VPC).
    • /24 = 256 addresses (standard for a subnet).
    • Always plan IP ranges across dev, staging, and prod so they don't overlap if you need to connect them later.

2. Subnets & The 5 Reserved AWS IPs

Subnets are slices of your VPC tied to one specific Availability Zone (building).

Inside every subnet you create, AWS automatically reserves 5 IP addresses for internal networking:

  • .0 — Network address.
  • .1 — VPC router / gateway.
  • .2 — AWS DNS resolver.
  • .3 — Reserved by AWS for future use.
  • .255 — Network broadcast address.

Rule of thumb: When you create a /24 subnet (which mathematically has 256 IPs), you will only get 251 usable IPs for your EC2 instances and databases (256 - 5 = 251). Notice how AWS explicitly displays "IP addresses available: 251" in the subnet details.


3. Route Tables: What Actually Makes a Subnet "Public"?

There is no special checkbox on AWS that makes a subnet public. Naming a subnet public-subnet does not make it public!

A subnet is Public if and only if its Route Table has a default route sending all outbound internet traffic (0.0.0.0/0) to an Internet Gateway (IGW):

Public Subnet Route Table             Private Subnet Route Table
Destination     Target                Destination     Target
10.0.0.0/16     local                 10.0.0.0/16     local
0.0.0.0/0       igw-0abc123           (No internet route - completely isolated)
Enter fullscreen mode Exit fullscreen mode

If a subnet has only the local route, instances inside it can talk to other servers in the VPC, but the outside internet has zero way in.


4. The Internet Gateway (IGW)

The Internet Gateway is the front security gate connecting your VPC to the public internet:

  • One IGW per VPC. It is horizontally scaled, highly available, and completely free.
  • It does 1:1 NAT translation between your instance's public IP and private IP.
  • When you run ip addr inside an EC2 instance, you will only see its private IP (10.0.1.x). The IGW handles the public IP translation seamlessly on the way in and out.

5. Security Groups vs. Network ACLs (NACLs)

AWS provides two layers of firewalls with very different rules:

Internet Traffic ──► [ Network ACL (Subnet Guard) ] ──► [ Security Group (Instance Guard) ] ──► EC2
Enter fullscreen mode Exit fullscreen mode
Feature Security Group (SG) Network ACL (NACL)
Protects Individual EC2 instance / ENI The entire Subnet boundary
Rules Allow rules only (default deny) Allow AND Deny rules
State Stateful: If traffic is allowed in, the reply is automatically allowed out. Stateless: You must explicitly allow both inbound and outbound return traffic!
Evaluation Evaluates all rules before deciding Evaluates rules in strict number order (100, 200... lowest number wins)

The 3-Tier Security Group Trick: Instead of hardcoding changing IP addresses into firewall rules, reference the Security Group ID directly:

  • web-sg: Inbound HTTP (80/443) from 0.0.0.0/0.
  • app-sg: Inbound port 8080 only from web-sg.
  • db-sg: Inbound port 5432 (Postgres) only from app-sg.

6. Official VPC Multi-Tier Architecture

Official AWS VPC Architecture with Public and Private Subnets
(Reference: Official AWS VPC User Guide Architecture)

In production:

  1. Public subnets host your load balancers and front-facing web servers.
  2. Private subnets host application workers and internal microservices.
  3. Isolated private subnets hold databases so no internet route ever touches your customer data.

Hands-On Practice & Console Walkthrough

Here is the step-by-step lab to build a custom VPC with public and private subnets, an Internet Gateway, and custom route tables in your AWS account.

Step 1: Create the Custom VPC (lab-vpc)

  1. In the VPC Console, go to Your VPCs → click Create VPC.
  2. Select VPC only.
  3. Name tag: lab-vpc.
  4. IPv4 CIDR block: 10.0.0.0/16 (gives us 65,536 total internal IPs).
  5. Leave Tenancy as Default and click Create VPC.

![Creating Custom VPC lab-vpc](

Fig 1: Creating my custom VPC lab-vpc with CIDR 10.0.0.0/16.


Step 2: Create Public & Private Subnets

Next, we divide the VPC into two separate subnets:

  1. Go to Subnets → Create subnet → select lab-vpc.
  2. Subnet 1 (Public):
    • Subnet name: public-subnet-1a
    • Availability Zone: Europe (Stockholm) / eun1-az1 (eu-north-1a)
    • IPv4 subnet CIDR block: 10.0.1.0/24 (251 usable IPs)
  3. Click Add new subnet for Subnet 2 (Private):
    • Subnet name: private-subnet-1a
    • Availability Zone: Europe (Stockholm) / eun1-az1 (eu-north-1a)
    • IPv4 subnet CIDR block: 10.0.2.0/24 (251 usable IPs)
  4. Click Create subnet.

![Configuring Public and Private Subnets](

Fig 2: Setting up public-subnet-1a and private-subnet-1a inside lab-vpc.


Step 3: Create & Attach the Internet Gateway (lab-igw)

A VPC is completely cut off from the internet by default. We need an Internet Gateway to open the front door:

  1. Go to Internet Gateways → click Create internet gateway.
  2. Name tag: lab-igw.
  3. Once created, click Actions → Attach to VPC.
  4. Select lab-vpc and click Attach internet gateway.

![Internet Gateway Attached to VPC](

Fig 3: Internet Gateway lab-igw created and attached to lab-vpc.


Step 4: Create the Public Route Table (public-rt)

Now we connect the public subnet to our Internet Gateway using a custom Route Table:

  1. Go to Route tables → click Create route table.
  2. Name tag: public-rt.
  3. VPC: Select lab-vpc and click Create route table.
  4. Open the Routes tab → click Edit routes → Add route:
    • Destination: 0.0.0.0/0 (any IPv4 traffic)
    • Target: Select Internet Gateway (lab-igw)
    • Click Save changes.
  5. Open the Subnet associations tab → Edit subnet associations → select public-subnet-1a and save.

(The private-subnet-1a stays connected to the default main route table with only the 10.0.0.0/16 local route, so it remains isolated).

![Public Route Table Creation](

Fig 4: Creating public-rt and linking it to lab-vpc.


Step 5: Launching an EC2 Instance into the Custom VPC

Finally, launch an EC2 instance directly inside your custom network:

  1. Go to EC2 → click Launch instance.
  2. Under Network settings, click Edit:
    • VPC: Select lab-vpc.
    • Subnet: Select public-subnet-1a. Notice that AWS confirms 251 available IPs.
    • Auto-assign public IP: Set to Enable if you want to reach it directly via SSH or web.
    • Firewall (security groups): Create a new security group allowing SSH (port 22) or HTTP (port 80).
  3. Click Launch instance.

![EC2 Network Settings in Custom Subnet](

Fig 5: Placing our EC2 instance into lab-vpc and public-subnet-1a with 251 available IPs.


Step 6: Clean Up (Avoid Surprise Bills!)

Once you finish testing:

  1. Terminate the EC2 instance.
  2. Go to Internet Gateways → detach lab-igw from lab-vpc, then delete it.
  3. Delete the custom route table public-rt.
  4. Delete the subnets and delete the VPC lab-vpc.

Top comments (0)