Design a Secure VPC on AWS

Build a two-tier VPC with public and private subnets, NAT Gateway, and layered security.

Introduction

30 Second Summary

Think about how a company protects its most sensitive systems. You wouldn't put your database server in the same room as the front desk where anyone can walk in.

In this project, you will design and build a secure Virtual Private Cloud (VPC) on AWS that separates public-facing resources from private ones, following the same architecture patterns used in production environments.

What You'll Build

A secure two-tier VPC architecture for the fictional company ABC Energy Ltd. that isolates a web server from a private application server using multiple layers of network security.

By the end of this project, you'll have:

  • A fully functional VPC with public and private subnets across two Availability Zones, following AWS Well-Architected best practices.
  • A working NAT Gateway enabling private resources to reach the internet for updates and API calls without being exposed to inbound traffic.
  • Configured layered security using Security Groups and tested EC2 connectivity proving the architecture works end-to-end.
  • Secret Mission: Configure custom Network ACLs with explicit allow/deny rules to add subnet-level defence-in-depth.

Are there any prerequisites?

You need an active AWS account with billing enabled. Basic familiarity with navigating the AWS Management Console is helpful, but every click is guided step by step.

Set Up and Understand CIDR Notation

Before you build any networking resources, you need to plan the address space your network will use. Every device in a network needs its own address, and CIDR notation is the system that defines how many addresses your network has available.

In this step, you will learn how CIDR notation works, then create the custom VPC that serves as ABC Energy Ltd.'s isolated private network on AWS.

In this step, get ready to:
  • Understand CIDR notation and the subnet addressing plan.
  • Navigate to the VPC Console in your chosen AWS Region.
  • Create the custom VPC for ABC Energy Ltd.
Understand CIDR notation and the subnet plan

Every VPC needs an IP address range that defines how many addresses are available for resources inside it. CIDR notation is the shorthand that specifies this range.

What is CIDR notation?

An IPv4 address has 4 octets (groups of 8 bits), for example 10.0.0.0. The number after the slash (called the "prefix length") tells you how many bits of the address are fixed.

For 10.0.0.0/16, the first 16 bits (the first two octets: 10.0) are locked. The remaining 16 bits can vary, giving you 2^16 = 65,536 possible addresses.

For 10.0.1.0/24, the first 24 bits (three octets: 10.0.1) are locked. Only the last 8 bits vary, giving 256 addresses. AWS reserves 5 per subnet, leaving 251 usable.

Here is the subnet plan for this project:

  • VPC: 10.0.0.0/16 (the entire address space, 65,536 addresses).
  • Public Subnet 1: 10.0.1.0/24 (addresses 10.0.1.0 through 10.0.1.255).
  • Public Subnet 2: 10.0.2.0/24 (addresses 10.0.2.0 through 10.0.2.255).
  • Private Subnet 1: 10.0.3.0/24 (addresses 10.0.3.0 through 10.0.3.255).
  • Private Subnet 2: 10.0.4.0/24 (addresses 10.0.4.0 through 10.0.4.255).

Why /24 for each subnet?

251 usable IPs is more than enough for a typical workload tier. The clean numbering (1, 2, 3, 4 in the third octet) makes the architecture easy to reason about at a glance.

Choose your AWS Region and navigate to the VPC Console
  • In the AWS Management Console, look at the top-right corner and select a Region. Use whichever Region is geographically closest to you, or us-east-1 if you are unsure.
  • Click the search bar at the top of the console and type VPC.
  • Select VPC from the results to open the VPC Dashboard.

What is that default VPC?

You will notice a default VPC already exists in your account. AWS creates one automatically in every Region so that you can launch resources without any setup. You will create a new, custom VPC alongside it for this project.

Create the VPC

The AWS Console offers a "VPC and more" wizard that creates the VPC, subnets, route tables, and gateways all in one click. You will choose "VPC only" so you can build each component individually and understand how they connect.

Why build piece by piece?

A real-world engineer might use the wizard for speed. For learning, creating each component separately helps you understand the dependency chain. If something breaks in production, you will know exactly which piece to troubleshoot.

  • From the VPC Dashboard, click Create VPC.
  • For Resources to create, select VPC only.
  • In the Name tag field, enter ABC-Energy-VPC.
  • For IPv4 CIDR block, select IPv4 CIDR manual input and enter 10.0.0.0/16.
  • For IPv6 CIDR block, select No IPv6 CIDR block.
  • For Tenancy, keep it set to Default.
  • Click Create VPC.

What did you just create?

The VPC is the logical boundary of your network. Nothing inside it can communicate with anything outside it unless you explicitly create a path (an Internet Gateway, NAT Gateway, VPN, or peering connection). This is isolation by default.

  • Navigate back to Your VPCs in the left navigation pane.
  • Confirm that ABC-Energy-VPC appears in the list with CIDR 10.0.0.0/16 and state Available.

Don't see your VPC?

Make sure you are looking at the correct Region in the top-right corner of the console. VPCs only appear in the Region where they were created.

If you see a CIDR conflict error, confirm you typed 10.0.0.0/16 exactly. A typo like 10.0.0.0/32 creates a single-address range that will not work for subnets.

Help me troubleshoot my VPC creation

Your VPC is ready. Next up, you will carve it into subnets, attach an Internet Gateway, and configure route tables to control traffic flow.

Create Subnets, Internet Gateway, and Route Tables

Your VPC exists, but it is an empty container. Resources need to live in subnets before they can communicate with each other or the outside world.

In this step, you will build the network skeleton: the subnets where resources will live, the gateway that connects your VPC to the internet, and the route tables that control traffic flow.

In this step, get ready to:
  • Create four subnets across two Availability Zones.
  • Create and attach an Internet Gateway.
  • Configure route tables that define which subnets are public and which are private.
Create all four subnets

Subnets divide your VPC's IP address space into smaller blocks. Each subnet lives in a single Availability Zone and will hold resources like EC2 instances.

  • In the VPC Console left navigation pane, click Subnets.
  • Click Create subnet.
  • Under VPC ID, select ABC-Energy-VPC.

Now configure the first subnet with these values:

  • Subnet name: ABC-Public-Subnet-1.
  • Availability Zone: select the first AZ in your region (for example, us-east-1a).
  • IPv4 subnet CIDR block: 10.0.1.0/24.
  • Click Add new subnet at the bottom of the form to add the remaining three subnets in the same creation flow.

Configure each additional subnet with these values:

  • Second subnet name: ABC-Public-Subnet-2, Availability Zone: the second AZ (for example, us-east-1b), CIDR: 10.0.2.0/24.
  • Third subnet name: ABC-Private-Subnet-1, Availability Zone: the first AZ (same as Public-1), CIDR: 10.0.3.0/24.
  • Fourth subnet name: ABC-Private-Subnet-2, Availability Zone: the second AZ (same as Public-2), CIDR: 10.0.4.0/24.
  • Click Create subnet.

You should see all four subnets listed with state Available.

Why two Availability Zones?

AWS best practice is to spread subnets across at least two Availability Zones for fault tolerance. If one AZ goes down, resources in the other AZ continue operating.

Next, enable auto-assign public IPv4 for the two public subnets only.

  • Select ABC-Public-Subnet-1 in the subnet list.
  • Click Actions, then Edit subnet settings.
  • Check the box labelled Enable auto-assign public IPv4 address.
  • Click Save.
  • Repeat these same four actions for ABC-Public-Subnet-2.

Why only public subnets get auto-assign?

Instances in public subnets need a public IP to be reachable from the internet. Private subnets deliberately do not get this setting because their resources should never be directly accessible from outside.

All subnets in the same AZ?

If you accidentally put all four subnets in the same Availability Zone, select each incorrect subnet, choose Actions, then Delete subnet, and recreate it in the correct AZ. Spreading across two AZs is essential for resilience.

Help me fix my subnet Availability Zone configuration.

Create and attach the Internet Gateway

An Internet Gateway is the door between your VPC and the public internet. Without it, nothing in your VPC can reach the internet.

  • In the left navigation pane, click Internet gateways.
  • Click Create internet gateway.
  • For Name tag, enter ABC-Energy-IGW.
  • Click Create internet gateway.

The gateway is created, but it is not yet connected to your VPC. Attach it now.

  • On the next screen, click Actions, then Attach to VPC.
  • Select ABC-Energy-VPC.
  • Click Attach internet gateway.

The state should change to Attached.

Does attaching the IGW give subnets internet access?

Simply attaching an Internet Gateway does not give any subnet internet access. You still need a route table entry pointing internet-bound traffic to the IGW.

This is what makes a subnet "public" in the next substep.

Create and configure route tables

A route table is a set of rules that determines where network traffic is directed. You will create two: one for public subnets (with a route to the IGW) and one for private subnets (without).

  • In the left navigation pane, click Route tables.

You will see a main route table that was auto-created with your VPC. You will create explicit route tables instead of using it.

  • Click Create route table.
  • For Name, enter ABC-Public-RT.
  • For VPC, select ABC-Energy-VPC.
  • Click Create route table.

Now add a route that sends all internet-bound traffic to the Internet Gateway.

  • With ABC-Public-RT selected, click the Routes tab.
  • Click Edit routes.
  • Click Add route.
  • For Destination, enter 0.0.0.0/0.
  • For Target, select Internet Gateway, then select ABC-Energy-IGW.
  • Click Save changes.

Now associate the public route table with the two public subnets.

  • Click the Subnet associations tab.
  • Click Edit subnet associations.
  • Check the boxes for ABC-Public-Subnet-1 and ABC-Public-Subnet-2.
  • Click Save associations.

Now create the private route table.

  • Click Create route table.
  • For Name, enter ABC-Private-RT.
  • For VPC, select ABC-Energy-VPC.
  • Click Create route table.

Associate it with the two private subnets.

  • Click the Subnet associations tab.
  • Click Edit subnet associations.
  • Check the boxes for ABC-Private-Subnet-1 and ABC-Private-Subnet-2.
  • Click Save associations.

What makes a subnet public or private?

A subnet with a route to an Internet Gateway is public. A subnet without that route is private. The subnet itself has no inherent "public" or "private" property.

A common misconception is that a subnet is public because it has a public IP. The route table is what actually determines whether internet-bound traffic can flow.

Verify your route tables by selecting each one and checking the Routes tab.

  • ABC-Public-RT should show two routes: 10.0.0.0/16 pointing to local and 0.0.0.0/0 pointing to igw-xxx.
  • ABC-Private-RT should show only the local route: 10.0.0.0/16 pointing to local.

Don't see the IGW route on the public table?

Make sure you added the route to ABC-Public-RT, not to ABC-Private-RT or the VPC's auto-created main route table. Select the correct route table, open the Routes tab, and click Edit routes to add the missing 0.0.0.0/0 entry pointing to the Internet Gateway.

Help me troubleshoot my route table configuration.

Your network skeleton is in place. Next up, you will deploy a NAT Gateway so that private subnet resources can reach the internet for updates without being exposed to inbound traffic.

Deploy NAT Gateway

Your VPC now has a clear network skeleton. Public subnets have a route to the Internet Gateway, and private subnets have no internet route at all.

But private resources still need to reach the internet for things like OS updates, patches, and external API calls. A NAT Gateway solves this by allowing outbound traffic from private subnets while blocking all inbound connections from the internet.

In this step, get ready to:
  • Allocate an Elastic IP address for the NAT Gateway.
  • Create the NAT Gateway in a public subnet.
  • Update the private route table to send internet-bound traffic through the NAT.
Allocate an Elastic IP address

A NAT Gateway needs a static public IP address so that external services see a consistent source address when private instances reach out to the internet. This static address is called an Elastic IP.

  • In the left navigation pane of the VPC Console, click Elastic IPs.
  • Click Allocate Elastic IP address.
  • Keep the defaults (Amazon's pool of IPv4 addresses).
  • Scroll down to Tags and add a Name tag with the value ABC-NAT-EIP.
  • Click Allocate.

You should see a green success banner confirming the Elastic IP allocation. The new address appears in the Elastic IPs list.

Why does a NAT Gateway need an Elastic IP?

The NAT Gateway translates private IP addresses to a public IP when traffic leaves for the internet. The Elastic IP gives it a fixed public address that never changes, even if the NAT Gateway is recreated.

This also means you can whitelist that single IP in external firewalls if needed.

Create the NAT Gateway
  • In the left navigation pane, click NAT Gateways.
  • Click Create NAT gateway.
  • Enter ABC-NAT-GW in the Name field.
  • For Subnet, select ABC-Public-Subnet-1.
  • For Connectivity type, select Public.
  • For Elastic IP allocation ID, select ABC-NAT-EIP from the dropdown.
  • Click Create NAT gateway.
  • Wait for the status to change from Pending to Available. This takes 1-2 minutes.

Why does the NAT Gateway sit in a public subnet?

This is a common source of confusion. The NAT Gateway itself needs to reach the internet (to forward traffic from private instances), so it must live in a subnet that has an IGW route.

The traffic flow works like this: Private Instance sends traffic to the NAT Gateway (via the private route table). The NAT Gateway forwards it to the Internet Gateway (via the public route table). The response travels back the same path in reverse.

NAT Gateway costs money

The NAT Gateway costs $0.045 per hour from the moment it is created, plus $0.045 per GB of data processed. You will delete it at the end of this project in the Before You Go section.

Don't see ABC-NAT-EIP in the dropdown?

Make sure you allocated the Elastic IP in the same Region as your VPC. If you switched Regions between creating the VPC and allocating the EIP, it will not appear.

Also confirm the Elastic IP is not already associated with another resource. An EIP can only be used by one resource at a time.

help me figure out why my Elastic IP isn't showing up when creating a NAT Gateway

Update the private route table

The NAT Gateway exists, but your private subnets do not know to send internet-bound traffic to it yet. You need to add a route to the private route table.

  • In the left navigation pane, click Route Tables.
  • Select ABC-Private-RT.
  • Click the Routes tab in the details panel below.
  • Click Edit routes.
  • Click Add route.
  • For Destination, enter 0.0.0.0/0.
  • For Target, select NAT Gateway, then select ABC-NAT-GW.
  • Click Save changes.

What does this route achieve?

The 0.0.0.0/0 destination means "all traffic not matched by a more specific route." By pointing it at the NAT Gateway, any instance in a private subnet that tries to reach the internet will have its traffic forwarded through the NAT.

The key security benefit is that this only works for outbound connections. Nothing on the internet can initiate an inbound connection to your private instances. This is controlled egress with zero ingress.

Confirm the route was added. ABC-Private-RT should now show two routes: the local route (10.0.0.0/16 > local) and the NAT route (0.0.0.0/0 > nat-xxx).

Don't see ABC-NAT-GW in the target dropdown?

Check that your NAT Gateway status is Available (not Pending). A NAT Gateway must fully provision before it appears as a valid route target. Wait a minute and try again.

Also confirm you are editing the route table in the same VPC where the NAT Gateway was created.

help me troubleshoot why my NAT Gateway doesn't appear as a route target

Your network plumbing is complete. Private instances can now reach the internet for updates and API calls, without being exposed to inbound traffic. Next up, you will launch EC2 instances and configure Security Groups to prove this architecture works end-to-end.

Launch EC2 Instances and Configure Security Groups

Your network plumbing is complete. Traffic can flow from the internet into public subnets, and private subnets can reach the internet through the NAT Gateway without being exposed to inbound connections.

Now it is time to put actual resources into this network and prove the architecture works. You will create Security Groups (your primary firewall layer), launch two EC2 instances (one public web server, one private app server), and then run connectivity tests that verify everything end-to-end.

In this step, get ready to:
  • Create two Security Groups with least-privilege rules and SG-referencing.
  • Launch a public web server and a private app server in the correct subnets.
  • Verify connectivity across all four network paths.
Create security groups

Security Groups act as virtual firewalls for your instances. Each rule specifies which traffic is allowed in or out. You will create two: one for the public web server and one for the private database server.

  • In the VPC console left navigation pane, click Security Groups.
  • Click Create security group.

Fill in the details for the web server security group:

  • Enter ABC-Web-SG in the Security group name field.
  • Enter Allows HTTP, HTTPS, and SSH from my IP in the Description field.
  • For VPC, remove the default VPC and select ABC-Energy-VPC.

Now add three inbound rules. Under Inbound rules, click Add rule for each:

  • Rule 1: Type SSH (port 22). Source: select My IP from the dropdown.
  • Rule 2: Type HTTP (port 80). Source: select Anywhere-IPv4 (0.0.0.0/0).
  • Rule 3: Type HTTPS (port 443). Source: select Anywhere-IPv4 (0.0.0.0/0).
  • Leave Outbound rules at the default (All traffic, 0.0.0.0/0).
  • Click Create security group.

What does My IP do?

When you select My IP as the source, the console auto-fills your current public IPv4 address with a /32 suffix. This means only your exact IP can SSH into the instance. No one else on the internet can reach port 22.

Now create the database security group. Return to Security Groups and click Create security group again.

  • Enter ABC-DB-SG in the Security group name field.
  • Enter Allows MySQL from web server only in the Description field.
  • For VPC, remove the default and select ABC-Energy-VPC.

For the inbound rule, you will reference the web server security group by its ID instead of using an IP address:

  • Click Add rule.
  • Type: select MYSQL/Aurora (port 3306).
  • Source: select Custom, then type sg- in the search field. The console will auto-complete with your security groups. Select the ID for ABC-Web-SG.
  • Leave Outbound rules at the default (All traffic, 0.0.0.0/0).
  • Click Create security group.

Why reference a Security Group instead of an IP?

By referencing ABC-Web-SG as the source, ANY instance attached to that security group can reach the database on port 3306. You do not need to update rules when instances are replaced, scaled, or receive new IPs.

This is how production AWS environments work. SG-referencing keeps your rules dynamic and resilient to change.

What makes Security Groups stateful?

Security Groups are stateful. If you allow inbound traffic on port 3306, the response traffic is automatically allowed out. You do not need a matching outbound rule for return traffic.

Launch EC2 instances

You will launch two instances: a public-facing web server that serves a test page, and a private app server that is only reachable from within the VPC.

  • Navigate to the EC2 service by searching EC2 in the top search bar.
  • In the left pane, click Instances.
  • Click Launch instances.

Configure the web server instance with these settings:

  • Enter ABC-Web-Server in the Name field.
  • Under Application and OS Images, select Amazon Linux 2023 (it should be the default, marked Free tier eligible).
  • Under Instance type, select whichever option shows Free tier eligible (t2.micro or t3.micro).

Which instance type is Free tier eligible?

AWS accounts created before July 15, 2025 get t2.micro free for 12 months. Accounts created on or after that date get t3.micro free for 6 months. Select whichever one shows the Free tier label in the console.

Next, create a key pair so you can SSH into your instances:

  • Under Key pair (login), click Create new key pair.
  • Enter abc-energy-key as the name.
  • Key pair type: RSA.
  • Private key file format: .pem.
  • Click Create key pair. The file downloads automatically. Save it somewhere you can find it (your Downloads folder is fine for now).

Keep your key pair safe

This .pem file is the only way to SSH into your instances. AWS will not let you download it again. If you lose it, you lose access.

Now configure the network settings for the web server:

  • Under Network settings, click Edit.
  • VPC: select ABC-Energy-VPC.
  • Subnet: select ABC-Public-Subnet-1.
  • Auto-assign public IP: select Enable.
  • Under Firewall (security groups), select Select existing security group.
  • Choose ABC-Web-SG from the list.

Finally, add a startup script that installs and runs a web server automatically:

  • Scroll down and expand Advanced details.
  • Scroll to the very bottom of that section and find the User data text box.
  • Paste the following script into the User data field:
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>ABC Energy Ltd. - Web Server</h1>" > /var/www/html/index.html

What does this script do?

This User data script runs once when the instance first boots. It updates the OS, installs the Apache web server (httpd), starts the service, enables it to survive reboots, and creates a simple HTML test page.

  • Click Launch instance.

Now launch the private app server. Click Launch instances again from the Instances page and configure it with different network settings:

  • Enter ABC-Private-Server in the Name field.
  • AMI: select Amazon Linux 2023 (same as before).
  • Instance type: select the same Free tier eligible type (t2.micro or t3.micro).
  • Key pair: select abc-energy-key (the key pair you already created).
  • Under Network settings, click Edit.
  • VPC: select ABC-Energy-VPC.
  • Subnet: select ABC-Private-Subnet-1.
  • Auto-assign public IP: select Disable.
  • Under Firewall (security groups), select Select existing security group.
  • Choose ABC-DB-SG from the list.
  • Do NOT add any User data for this instance.
  • Click Launch instance.
  • Return to the Instances list. Wait for both instances to show a Running state and 2/2 checks passed under Status check (this takes 2-3 minutes).

Instance stuck in Pending?

Instances typically take 1-3 minutes to reach Running state. If an instance fails to start, check that you selected a subnet inside ABC-Energy-VPC (not the default VPC) and that the selected instance type is available in your region.

Help me troubleshoot my EC2 instance that won't start.

Verify connectivity across all network paths

Your architecture is only proven once traffic actually flows through it. You will run four tests that confirm the public web server is reachable, the private server is isolated, and the NAT Gateway works.

Test 1: Confirm the web server is publicly accessible.

  • In the EC2 Instances list, select ABC-Web-Server.
  • Copy the Public IPv4 address from the details panel.
  • Open a new browser tab and navigate to:
http://[[EC2_PUBLIC_IP="your web server's public IPv4 address"]]

You should see a page displaying "ABC Energy Ltd. - Web Server" in large text. This confirms the Internet Gateway, public route table, security group, and web server are all working together.

Page not loading?

Make sure you are using http:// (not https). The User data script only installs HTTP on port 80. Also confirm your security group ABC-Web-SG has an inbound rule allowing HTTP from 0.0.0.0/0. If the instance just launched, wait 2-3 minutes for the User data script to finish installing Apache.

Help me troubleshoot why my web server page is not loading.

Test 2: SSH into the web server.

  • Open a terminal on your computer. On macOS, press Cmd+Space and type Terminal. On Windows, press the Windows key and type PowerShell.
  • Navigate to the folder where you saved your abc-energy-key.pem file (likely your Downloads folder).
  • Connect to the web server using SSH agent forwarding by running:
ssh -A -i [[PEMPATH="path/to/abc-energy-key.pem"]] ec2-user@[[EC2_PUBLIC_IP="your web server's public IPv4 address"]]

Why the -A flag?

The -A flag enables SSH agent forwarding. This lets you SSH from the web server to the private server without copying your private key onto the web server. In production, you would use AWS Systems Manager Session Manager instead of copying keys between servers.

  • When prompted with "Are you sure you want to continue connecting?", type yes and press Enter.

You should see a welcome message from Amazon Linux. You are now inside the web server.

Permission denied or connection timed out?

If you see "Permission denied", your .pem file permissions may be too open. On macOS/Linux, run chmod 400 abc-energy-key.pem first. If the connection times out, confirm that the SSH inbound rule in ABC-Web-SG uses your current IP. Your IP may have changed since you created the rule.

Help me fix my SSH connection to the EC2 web server.

Test 3: From the web server, confirm the network path to the private server is open.

  • In the EC2 console, select ABC-Private-Server and copy its Private IPv4 address (it will look like 10.0.3.x).
  • While still SSH'd into the web server, run this command to test port 3306 connectivity:
nc -zv [[PRIVATE_IP="your private server's private IPv4 address"]] 3306

What should I see?

You will see "Connection refused". This is actually a success signal. "Connection refused" means the network path is open (traffic reached the server) but no MySQL service is listening on that port. If you saw "Connection timed out" instead, that would mean the network is blocking the traffic.

Test 4: Confirm the private server can reach the internet via the NAT Gateway.

  • From the web server (where you are still SSH'd in), SSH into the private server using its private IP:
ssh ec2-user@[[PRIVATE_IP="your private server's private IPv4 address"]]
  • Type yes when prompted to continue connecting.
  • Once inside the private server, test outbound internet access by running:
curl -I https://aws.amazon.com

You should see HTTP response headers (starting with something like HTTP/2 200 or a 301 redirect). This proves the private server reached the internet through the NAT Gateway without having a public IP itself.

Curl hanging or connection timed out?

Verify that ABC-Private-RT has a 0.0.0.0/0 route pointing to ABC-NAT-GW. Also confirm the NAT Gateway status is Available (not Pending or Failed). If you just created the NAT Gateway, give it another minute.

Help me troubleshoot why my private server cannot reach the internet through the NAT Gateway.

What did these four tests prove?

Test 1 proved the public subnet, Internet Gateway, route table, and Security Group work together to serve web traffic. Test 2 proved SSH access is restricted to your IP only.

Test 3 proved the private server accepts traffic from the web server (via SG-referencing) on port 3306. Test 4 proved the NAT Gateway provides controlled outbound internet access to private resources.

Secret mission

Configure Custom Network ACLs

Your Security Groups are doing great work at the instance level. But what if someone accidentally opens a Security Group rule too wide? Network ACLs add a second line of defence at the subnet level. In this secret mission, you will configure custom NACLs with explicit allow and deny rules to implement true defence-in-depth.

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. This project uses a NAT Gateway and public IPv4 addresses that incur ongoing hourly charges.

Cost warning

The NAT Gateway costs $0.045 per hour ($1.08/day) from the moment it was created. Each public IPv4 address costs $0.005 per hour. Your project currently has two public IPv4 addresses (the web server and the NAT Gateway's Elastic IP).

If you are not continuing immediately, delete your resources to avoid unexpected charges.

Resources you used:

  • ABC-Energy-VPC (includes subnets, route tables, security groups, NACLs, and Internet Gateway).
  • ABC-NAT-GW (NAT Gateway, main cost driver).
  • ABC-NAT-EIP (Elastic IP address).
  • ABC-Web-Server and ABC-Private-Server (EC2 instances).
  • abc-energy-key (key pair in AWS and .pem file on your local machine).

Keep everything running

No action needed. Choose this if you are still actively building or plan to continue within the next few hours.

Be aware that costs will accumulate. The NAT Gateway alone costs approximately $1.08 per day, plus $0.24 per day for the two public IPv4 addresses.

Pause - I'll come back to this later

Stop your EC2 instances to avoid compute charges. Note that you cannot pause a NAT Gateway. It continues to incur charges until deleted.

  • Navigate to EC2 > Instances.
  • Select both ABC-Web-Server and ABC-Private-Server.
  • Click Instance state > Stop instance.
  • Wait for both instances to show Stopped status.

What still costs money while paused?

Stopped instances do not incur compute charges, but EBS storage volumes still accrue small charges. The NAT Gateway ($0.045/hour) and public IPv4 addresses ($0.005/hour each) continue charging until deleted or released.

If you will be away for more than a day, consider deleting the NAT Gateway and Elastic IP to stop the main charges. You can recreate them when you return.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow this order to avoid dependency errors.

Step 1: Terminate EC2 instances.

  • Navigate to EC2 > Instances.
  • Select both ABC-Web-Server and ABC-Private-Server.
  • Click Instance state > Terminate instance.
  • Wait for both instances to show Terminated status before proceeding.

Step 2: Delete the NAT Gateway.

  • Navigate to VPC > NAT gateways.
  • Select ABC-NAT-GW.
  • Click Actions > Delete NAT gateway.
  • Type delete in the confirmation field and click Delete.
  • Wait for the NAT Gateway status to show Deleted (this takes 1-2 minutes).

Step 3: Release the Elastic IP address.

  • Navigate to VPC > Elastic IP addresses.
  • Select ABC-NAT-EIP.
  • Click Actions > Release Elastic IP addresses.
  • Click Release to confirm.

Step 4: Delete the VPC.

  • Navigate to VPC > Your VPCs.
  • Select ABC-Energy-VPC.
  • Click Actions > Delete VPC.
  • The confirmation screen shows all resources that will be deleted (subnets, route tables, security groups, network ACLs, and the Internet Gateway). Type delete and click Delete.

Step 5: Delete the key pair.

  • Navigate to EC2 > Key Pairs.
  • Select abc-energy-key.
  • Click Actions > Delete.
  • Type Delete in the confirmation field and click Delete.

Step 6: Delete the local .pem file.

  • Delete the abc-energy-key.pem file from your local machine (check your Downloads folder).

Why does order matter?

EC2 instances must terminate before the NAT Gateway can be deleted, because active routes still reference it. The NAT Gateway must be deleted before the Elastic IP can be released, because the EIP is still associated with the NAT Gateway.

Deleting the VPC cascades to subnets, route tables, security groups, network ACLs, and detaches the Internet Gateway automatically.

Nice Work!

Nice Work!

Nice work! You just designed and deployed a production-style VPC architecture on AWS from scratch, complete with network segmentation, controlled internet access, and layered security.

You've learned how to:

  • Built a two-tier VPC architecture with public and private subnets across two Availability Zones, using CIDR notation to plan your IP address space and route tables to define what makes a subnet public or private.
  • Deployed a NAT Gateway to give private resources controlled outbound internet access while keeping them completely unreachable from the public internet.
  • Implemented Security Groups with least-privilege rules and SG-referencing, then launched EC2 instances and verified end-to-end connectivity across the architecture.
  • Secret Mission: Configured custom Network ACLs with explicit allow and deny rules, demonstrating stateless subnet-level filtering with ephemeral port rules for defence-in-depth.

Ready to quiz yourself?