Creating a Private Subnet in Your VPC
Add a private subnet, route table, and network ACL to your VPC.
Introduction
30 Second Summary
Think about how a building has a public lobby and restricted back offices. Visitors can walk into the lobby, but the sensitive operations happen in rooms with no public entrance.
In this project, you will extend your existing VPC by adding a private subnet, a dedicated route table, and a custom network ACL. Together, these create a secure, isolated area inside your VPC where internal resources like databases can live without any direct internet exposure.
What You'll Build
When you finish, you will have the classic public/private VPC architecture used in production environments. You can open the VPC console and confirm that your private subnet has no internet route and a deny-all firewall, while your public subnet still works exactly as before.
By the end of this project, you'll have:
- A private subnet in a separate Availability Zone where any launched resource gets only a private IP address. You can verify in the console that it has no public IP assignment and sits in a completely separate IP range from your public subnet.
- A dedicated route table with only local VPC traffic allowed. You can inspect the routes and confirm there is no internet gateway entry, proving the subnet is truly private.
- A custom network ACL that denies all inbound and outbound traffic by default. You can check the rules and see only deny-all entries, enforcing least-privilege until you explicitly open specific traffic in a future project.
- Secret Mission: Create a second private subnet in a different Availability Zone using the AWS CLI in CloudShell, proving you can manage VPC networking programmatically.
Are there any prerequisites?
This project builds on an existing VPC setup. You need a VPC with CIDR 10.0.0.0/16, a public subnet (10.0.0.0/24), an internet gateway attached to the VPC, and a route table with a 0.0.0.0/0 route pointing to that internet gateway.
You also need an AWS account with an IAM admin user. If you completed the earlier VPC project in this series, you already have everything you need.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters.
Your existing VPC has a public subnet where resources are exposed to the internet. Production environments need a separate, locked-down area for sensitive resources like databases and backend services. That's what you'll create today.
Verify Your Existing VPC Setup
Your VPC is the foundation for everything you build in this project. Before adding a private subnet, you need to confirm the resources from your earlier project are still in place.
If anything is missing or misconfigured, wiring in a private subnet later will cause confusing errors. In this step, you will sign into the AWS console and verify your VPC, public subnet, internet gateway, and route table are all configured correctly.
In this step, get ready to:
- Sign in to the AWS Management Console and navigate to the VPC console.
- Confirm your VPC, public subnet, and internet gateway exist.
- Verify your public route table has the correct routes and subnet association.
Sign in and navigate to the VPC console
- Open your browser and sign in to the AWS Management Console with your IAM admin user.
- In the search bar at the top of the console, type VPC and press Enter.
- Select VPC from the search results to open the VPC console.
You should now see the VPC dashboard. This is the central hub for managing all your networking resources.
Confirm your VPC, subnet, and internet gateway
- In the left navigation pane, select Your VPCs.
- Confirm your VPC exists with the IPv4 CIDR block 10.0.0.0/16.
- In the left navigation pane, select Subnets.
- Confirm your public subnet exists with the CIDR block 10.0.0.0/24.
- In the left navigation pane, select Internet gateways.
- Confirm your internet gateway exists and its State column shows Attached. The VPC ID column should show your VPC.
Why does the internet gateway need to be attached?
An internet gateway is the bridge between your VPC and the public internet. If it exists but is not attached to your VPC, no resource in any subnet can send or receive internet traffic.
Missing a resource?
If any of these resources are missing, you need to complete the earlier VPC project first. That project creates the VPC, public subnet, and internet gateway that this project builds on.
Help me figure out which VPC resources I'm missing and how to create them.
Verify your route table and subnet association
The route table is what determines whether a subnet is public or private. Your public subnet's route table should have a route that sends internet-bound traffic to the internet gateway.
- In the left navigation pane, select Route tables.
- Select the checkbox next to your public route table.
- Select the Routes tab in the details panel below.
- Confirm you see two routes:
- Select the Subnet associations tab.
- Under Explicit subnet associations, confirm your public subnet (10.0.0.0/24) is listed.
What makes a subnet public?
A subnet is public when its route table has a route to an internet gateway. The 0.0.0.0/0 route is the key. It means "any traffic not destined for the VPC itself, send it to the internet gateway."
In the next step, you will create a subnet with NO such route, making it private by design.
Before you move on, predict: what do you think would happen if your private subnet accidentally used this same route table?
It would become public. Any resource launched in that subnet would be reachable from the internet. That is exactly why you will create a separate route table in Step 3.
Everything checks out. Your VPC has a solid public subnet setup. Next up, you will create a private subnet that is completely isolated from the internet.
Create the Private Subnet
Your VPC is confirmed and ready. Now it's time to carve out a private area inside it for resources that should never be directly exposed to the internet.
Right now, your VPC only has a public subnet. Every resource you launch there gets a path to the internet through the route table's internet gateway route. Resources like databases and backend services need a separate, isolated zone with no internet access. That's exactly what a private subnet provides.
In this step, get ready to:
- Attempt to create a subnet and discover why CIDR blocks cannot overlap.
- Create a private subnet with a unique CIDR block in a different Availability Zone.
- Confirm the subnet has no public IP auto-assignment.
Create a subnet in your VPC
You need a new subnet that lives in a different Availability Zone than your public subnet. Spreading subnets across AZs is a production best practice for resilience.
- In the VPC console left navigation pane, select Subnets.
- Select Create subnet.
- For VPC ID, select your VPC from the dropdown.
- Set the Subnet name to Private 1.
- For Availability Zone, select the second AZ in the list (different from the one your public subnet uses).
- For IPv4 subnet CIDR block, enter 10.0.0.0/24.
Before you select Create subnet, what do you think will happen? You've entered 10.0.0.0/24, the same CIDR block as your existing public subnet.
- Select Create subnet.
You see an error: CIDR Address overlaps with existing Subnet CIDR: 10.0.0.0/24. This is expected.
Why can't subnets share a CIDR block?
Each subnet in a VPC owns a range of IP addresses defined by its CIDR block. If two subnets claimed the same range, AWS would have no way to know which subnet an IP address belongs to.
Your public subnet already owns 10.0.0.0/24 (addresses 10.0.0.0 to 10.0.0.255). Your private subnet needs its own unique slice of the VPC's address space.
Fix the CIDR overlap
- Clear the IPv4 subnet CIDR block field.
- Enter 10.0.1.0/24 as the new CIDR block.
- Select Create subnet.
This time the subnet creates successfully. You should see a green success banner at the top of the page.
What does 10.0.1.0/24 mean?
This CIDR block gives your private subnet IP addresses from 10.0.1.0 to 10.0.1.255. That's completely separate from your public subnet's range (10.0.0.0 to 10.0.0.255).
Both subnets live inside the VPC's larger 10.0.0.0/16 range, but each occupies its own non-overlapping slice.
Still seeing an error?
Double-check you typed 10.0.1.0/24 (with a 1 in the third octet), not 10.0.0.0/24. Also confirm you selected the correct VPC in the VPC ID dropdown.
Help me fix my subnet CIDR error
Confirm your private subnet settings
Your subnet is created, but there's one important difference between this subnet and your public one. Unlike the public subnet, you are NOT enabling Auto-assign public IPv4 address for this subnet.
- In the Subnets list, select the checkbox next to your Private 1 subnet.
- In the details panel below, check the Auto-assign public IPv4 address field. Confirm it shows No.
- Confirm the IPv4 CIDR shows 10.0.1.0/24.
- Confirm the Availability Zone is different from your public subnet's AZ.
What do you expect to happen if you launched an EC2 instance in this subnet right now? Would it be reachable from the internet?
Resources launched in this subnet will only receive private IP addresses. Without a public IP, they are unreachable from the internet. This is exactly what you want for internal resources like databases.
Why disable auto-assign public IP?
A public IP makes a resource addressable from anywhere on the internet. By leaving auto-assign off, you guarantee that nothing in this subnet gets a public address by default. Combined with the private route table you'll create next, this makes the subnet truly private.
Your private subnet exists, but it's not truly isolated yet. It's still using the VPC's main route table, which might have a route to the internet. Next up, you'll create a dedicated route table that keeps all traffic locked inside the VPC.
Create a Private Route Table
Your private subnet exists, but it is not truly private yet. Right now, it is implicitly associated with your VPC's main route table, which has a route to your internet gateway. Any subnet associated with that route table can send traffic directly to the internet.
To truly isolate your private subnet, you need a dedicated route table that only allows traffic within the VPC. In this step, you will create that route table and wire it to your private subnet.
In this step, get ready to:
- Create a private route table with no internet route.
- Verify the route table only allows local VPC traffic.
- Associate the private subnet with the new route table.
Create the route table
A route table is a set of rules that determines where network traffic is directed. Your public route table has a rule that sends all non-local traffic (0.0.0.0/0) to the internet gateway. Your private route table will have no such rule.
- In the left navigation pane of the VPC console, select Route tables.
- Select Create route table.
- In the Name field, enter Private Route Table.
- For VPC, select your VPC (10.0.0.0/16).
- Select Create route table.
You should see a success banner confirming the route table was created.
Verify the route table has no internet route
The whole point of a private route table is that it has no path to the internet. Let's confirm this is the case.
- Select your new Private Route Table from the route tables list.
- Select the Routes tab in the details panel below.
Before you look, think about what you expect to see. How many routes should appear, and what should they point to?
You should see only a single route: Destination 10.0.0.0/16 with Target local. There is no 0.0.0.0/0 route. Traffic from this route table can only flow within the VPC.
What makes a subnet public or private?
A subnet is "public" if its associated route table has a route to an internet gateway (0.0.0.0/0 targeting igw-xxx). A subnet is "private" if its route table has no such route.
Compare this to your public route table, which has both the 10.0.0.0/16 local route AND the 0.0.0.0/0 internet gateway route. That single extra route is the difference between public and private.
Associate the private subnet with the route table
A route table does nothing until a subnet is associated with it. Right now, your "Private 1" subnet is still using the VPC's default route table. You need to explicitly wire it to the new private route table.
- Select the Subnet associations tab.
- Under Explicit subnet associations, select Edit subnet associations.
- Select the checkbox next to your Private 1 subnet.
- Select Save associations.
Your private subnet is now wired to a route table that keeps all traffic inside the VPC.
Why explicit association matters
Without an explicit association, a subnet falls back to the VPC's main route table. If that main route table has an internet route, your "private" subnet would actually be public. Explicit associations remove this ambiguity.
Now confirm the association took effect. What do you expect to see in the Subnet associations tab?
- On the Subnet associations tab, confirm that Private 1 now appears under Explicit subnet associations.
Don't see Private 1 in the associations?
Make sure you selected the correct route table. If you are viewing the public route table instead, your public subnet will show up in the associations. Return to the Route tables list and select the one named Private Route Table.
If the subnet does not appear, select Edit subnet associations again and verify the checkbox next to Private 1 is selected before saving.
Still stuck? Why isn't my subnet showing under the Private Route Table associations?
Your private subnet now has its own route table that blocks all internet-bound traffic. But there is still one more layer of protection to add. Next up, you will create a custom network ACL that denies all traffic by default.
Create a Private Network ACL
Your private subnet now has a route table that blocks internet access. But the subnet is still using the VPC's default network ACL, which allows all inbound and outbound traffic.
If any part of your VPC gets compromised, an attacker could exploit that permissive ACL to reach your private resources. A custom network ACL that denies everything by default adds a second layer of protection. In this step, you will create that restrictive NACL and attach it to your private subnet.
In this step, get ready to:
- Create a custom network ACL with deny-all rules.
- Inspect the deny-all inbound and outbound rules that come with a custom NACL.
- Associate your private subnet with the new NACL.
Create the network ACL
Your private subnet currently inherits the VPC's default network ACL. The default NACL allows all traffic in both directions. You need a custom NACL that starts from a deny-all posture.
- In the left navigation pane, select Network ACLs.
- Select Create network ACL.
- For Name, enter Private NACL.
- For VPC, select your VPC.
- Select Create network ACL.
You should see a success banner confirming the network ACL was created.
What is a network ACL?
A network ACL is a firewall that controls traffic at the subnet level. It evaluates rules in order by rule number and either allows or denies each packet.
Every VPC comes with a default NACL that allows all traffic. Custom NACLs are the opposite. They deny all inbound and outbound traffic until you explicitly add allow rules.
Inspect the deny-all rules
Before you think about what rules to add, take a look at what your custom NACL starts with. This is the critical difference between default and custom NACLs.
- Select the checkbox next to your new Private NACL.
- Select the Inbound rules tab.
What do you expect to see here? Think about what a custom NACL starts with before you look.
You should see only a single rule with an asterisk (*) that denies all traffic. There are no allow rules.
- Now select the Outbound rules tab.
The outbound rules show the same thing. Only a deny-all (*) rule. No traffic can enter or leave any subnet associated with this NACL.
Why is deny-all the right starting point?
This is the principle of least privilege applied at the network level. By starting with everything blocked, you only open the exact ports and protocols you need.
You will configure specific allow rules in a later project when you launch resources into this subnet and know exactly which traffic to permit.
Associate the NACL with your private subnet
Your NACL exists, but it is not protecting anything yet. You need to associate it with your private subnet so it replaces the default allow-all NACL.
- Select the Subnet associations tab.
- Select Edit subnet associations.
- Select the checkbox next to your Private 1 subnet.
- Select Save changes.
Your private subnet is now protected by a NACL that denies all traffic by default.
Why use both a route table and a NACL?
This is defense-in-depth. The route table prevents internet access by having no route to the internet gateway. The NACL adds a second barrier that blocks all traffic even within the VPC until you explicitly allow it.
If an attacker compromises your public subnet and tries to move laterally, the NACL on your private subnet blocks that attempt. Two independent controls are harder to defeat than one.
Let's confirm everything is wired correctly. Return to the Network ACLs page and select your Private NACL.
- Check the Inbound rules tab. You should see only the deny-all (*) rule.
- Check the Outbound rules tab. You should see only the deny-all (*) rule.
- Check the Subnet associations tab. You should see Private 1 listed under Subnets associated with this network ACL.
Don't see Private 1 in the subnet associations?
Make sure you selected the checkbox next to Private 1 (not your public subnet) and clicked Save changes. If you accidentally associated the NACL with your public subnet, your public subnet will lose all connectivity.
Help me fix my NACL subnet association
Your VPC now has the classic public/private architecture used in production environments. The public subnet has internet access, while the private subnet is locked down by both a local-only route table and a deny-all NACL.
Secret mission
Create a Second Private Subnet Using AWS CLI
Production architectures spread resources across multiple Availability Zones for resilience. In this secret mission, you will use the AWS CLI via CloudShell to create a second private subnet, learning to manage VPC resources programmatically.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. All resources created in this project (private subnets, route tables, and network ACLs) are completely free with no hourly charges or data processing fees.
Resources you used:
- 1 private subnet (Private 1) in your VPC.
- 1 private route table (Private Route Table) associated with the private subnet.
- 1 custom network ACL (Private NACL) associated with the private subnet.
- Secret Mission: 1 additional private subnet (Private 2) created via AWS CLI.
Keep everything running
No action needed. Choose this if you plan to continue with the next project in the series (Launching VPC Resources). All resources created today are free, so there is nothing to worry about cost-wise.
- Your VPC now has both public and private subnets ready for launching resources.
- No charges apply to subnets, route tables, or network ACLs regardless of how long they exist.
Pause - I'll come back to this later
Since subnets, route tables, and NACLs incur no charges, pausing is identical to keeping everything running. There are no processes to stop or resources to shut down.
- Leave all resources as they are. They cost nothing whether active or idle.
- When you return, navigate to the VPC console and confirm your private subnet, route table, and NACL are still in place.
Delete - I don't want to use this again
Remove all project resources and start fresh. You have two options: delete only today's resources (preserving your public subnet setup from the earlier project), or delete the entire VPC.
Option A: Delete only today's resources
This preserves your VPC, public subnet, internet gateway, and public route table from the earlier project.
- In the VPC console, select Network ACLs from the left navigation pane.
- Select the checkbox next to Private NACL.
- Select the Subnet associations tab, then Edit subnet associations.
- Deselect all subnets and select Save changes.
- With Private NACL still selected, choose Actions, then Delete network ACL.
- Select Route tables from the left navigation pane.
- Select the checkbox next to Private Route Table.
- Select the Subnet associations tab, then Edit subnet associations.
- Deselect all subnets and select Save associations.
- With Private Route Table still selected, choose Actions, then Delete route table.
- Select Subnets from the left navigation pane.
- Select the checkbox next to Private 1 (and Private 2 if you completed the Secret Mission).
- Choose Actions, then Delete subnet. Confirm the deletion.
Option B: Delete the entire VPC
This removes the VPC and all associated resources, including your public subnet and internet gateway from the earlier project.
- In the VPC console, select Your VPCs from the left navigation pane.
- Select your VPC (CIDR 10.0.0.0/16).
- Choose Actions, then Delete VPC.
- This deletes the VPC and all associated subnets, route tables, internet gateways, and NACLs. Confirm the deletion.
Nice Work!
Nice Work!
Nice work! You just built the classic public/private network architecture used in production AWS environments.
Here's what you accomplished:
- Created a private subnet with a non-overlapping CIDR block (10.0.1.0/24), learning why subnets in the same VPC must have unique IP address ranges.
- Built a dedicated private route table with no internet gateway route, understanding how route tables determine whether a subnet is public or private.
- Configured a custom network ACL with default-deny rules, enforcing defense-in-depth by layering route table isolation with a restrictive NACL that blocks lateral movement within the VPC.
- Secret Mission: Created a second private subnet using the AWS CLI via CloudShell, learning to manage VPC resources programmatically and design multi-AZ architectures for resilience.
Ready to quiz yourself?