Design a Secure VPC on AWS
Build a multi-tier VPC with public and private subnets, IGW, and NAT Gateway.
Introduction
30 Second Summary
Every company stores sensitive data behind locked doors. In the cloud, those locked doors are virtual networks that separate public-facing systems from private databases and backend servers.
In this project, you will design and build a production-style Virtual Private Cloud (VPC) on AWS for a fictional company migrating to the cloud. You will create subnets, gateways, route tables, and security rules that keep web servers accessible to the public while locking down private backend servers.
What You'll Build
A multi-tier VPC architecture for ABC Energy Ltd. that separates public web servers from private database servers using distinct subnets, route tables, and layered security controls.
By the end of this project, you'll have:
- A fully configured VPC with public and private subnets spread across two Availability Zones, connected to the internet through an Internet Gateway and NAT Gateway.
- Layered security controls using Security Groups and Network ACLs that enforce least-privilege access between your public and private tiers.
- Two EC2 instances (a web server and a database server) with verified connectivity proving your network architecture works end-to-end.
- Secret Mission: Enable VPC Flow Logs to CloudWatch and analyze traffic patterns between your public and private tiers.
Are there any prerequisites?
You need an AWS account with console access. No prior VPC experience is required, but familiarity with the AWS Management Console will help you move faster.
Create the VPC and Subnets
ABC Energy Ltd. is migrating to AWS and needs a secure network foundation that separates public-facing resources from private backend systems. A VPC (Virtual Private Cloud) is your own isolated section of the AWS cloud where you define the network layout.
In this step, you'll create a VPC and divide it into four subnets spread across two Availability Zones. This gives ABC Energy both security isolation and high availability from the start.
In this step, get ready to:
- Sign in to the AWS Management Console and navigate to the VPC Console.
- Create a VPC with CIDR block 10.0.0.0/16.
- Create four subnets (2 public, 2 private) across two Availability Zones.
Navigate to the VPC Console
The VPC Console is where you build and manage all your networking resources on AWS.
- Sign in to the AWS Management Console at https://console.aws.amazon.com.
- In the search bar at the top, type VPC and select VPC from the results.
- Check the Region selector in the top-right corner of the console.
- Select your preferred region (e.g., US East (N. Virginia) us-east-1).
- Confirm you can see the VPC Dashboard page.
Why does the region matter?
AWS resources live in a specific region. All the resources you create in this project must be in the same region, otherwise they won't be able to find each other.
Don't see the VPC Dashboard?
Make sure you selected VPC (not VPN or another service) from the search results. The dashboard should show sections like Your VPCs, Subnets, and Route tables in the left navigation panel.
Help me find the VPC Dashboard in the AWS Console.
Create the VPC
A VPC needs a CIDR block that defines the total range of IP addresses available inside it. You'll use 10.0.0.0/16, which gives you over 65,000 addresses to work with.
- On the VPC Dashboard, click Create VPC.
- For Resources to create, select VPC only.
- For Name tag, enter ABCEnergy-VPC.
- For IPv4 CIDR block, select IPv4 CIDR manual input and enter 10.0.0.0/16.
- For IPv6 CIDR block, leave it as No IPv6 CIDR block.
- For Tenancy, leave it as Default.
- Click Create VPC.
You should see a green success banner confirming that your VPC has been created.
Why VPC only instead of VPC and more?
The VPC and more option auto-creates subnets, route tables, and gateways in one click. That skips the learning entirely.
Creating each component manually teaches you the dependency chain between VPC resources. This understanding is critical for troubleshooting real production networks.
What is a CIDR block?
A CIDR block defines a range of IP addresses using compact notation. 10.0.0.0/16 means all addresses from 10.0.0.0 to 10.0.255.255 (65,536 addresses total).
The number after the slash (/16) tells you how many bits are fixed. A smaller number means more addresses available.
Seeing an error when creating the VPC?
Double-check that you typed 10.0.0.0/16 exactly, including the forward slash and number. Make sure you selected IPv4 CIDR manual input (not the IPAM option).
Help me troubleshoot my VPC creation error.
Create four subnets
Subnets divide your VPC into smaller network segments. Public subnets will hold internet-facing servers, while private subnets will hold backend systems that should never be directly reachable from the internet.
- In the left navigation panel, click Subnets.
- Click Create subnet.
- For VPC ID, select ABCEnergy-VPC from the dropdown.
Now configure the first subnet. You'll add the remaining three using the Add new subnet button within the same wizard.
- For Subnet name, enter Public-Subnet-1.
- For Availability Zone, select the first zone in your region (e.g., us-east-1a).
- For IPv4 subnet CIDR block, enter 10.0.1.0/24.
- Click Add new subnet to add the second subnet.
- For Subnet name, enter Public-Subnet-2.
- For Availability Zone, select the second zone in your region (e.g., us-east-1b).
- For IPv4 subnet CIDR block, enter 10.0.2.0/24.
- Click Add new subnet to add the third subnet.
- For Subnet name, enter Private-Subnet-1.
- For Availability Zone, select the first zone (e.g., us-east-1a).
- For IPv4 subnet CIDR block, enter 10.0.3.0/24.
- Click Add new subnet to add the fourth subnet.
- For Subnet name, enter Private-Subnet-2.
- For Availability Zone, select the second zone (e.g., us-east-1b).
- For IPv4 subnet CIDR block, enter 10.0.4.0/24.
- Click Create subnet.
You should see all four subnets listed on the Subnets page with their correct CIDR blocks and Availability Zones.
Why two Availability Zones?
Each Availability Zone is a physically separate data centre with its own power and networking. Spreading subnets across two zones means your application stays up even if one zone has an outage.
The /24 CIDR on each subnet gives you 256 addresses (251 usable after AWS reserves 5).
Now you need to enable auto-assign public IPv4 on the two public subnets. This ensures that any instance launched in those subnets automatically receives a public IP address.
- Select the checkbox next to Public-Subnet-1.
- Click Actions.
- Click Edit subnet settings.
- Check the box for Enable auto-assign public IPv4 address.
- Click Save.
Now repeat the same process for the second public subnet.
- Select the checkbox next to Public-Subnet-2.
- Click Actions.
- Click Edit subnet settings.
- Check the box for Enable auto-assign public IPv4 address.
- Click Save.
Why enable auto-assign public IPv4?
Without this setting, instances in public subnets won't get a public IP address automatically. They would be unreachable from the internet even if the routing is correct.
Private subnets don't need this setting because their instances should never be directly accessible from outside the VPC.
Don't see your subnets listed?
Make sure you selected ABCEnergy-VPC as the VPC when creating subnets. If you used a different VPC, the subnets won't appear under the correct filter.
Also check that the CIDR blocks don't overlap. Each subnet must have a unique CIDR range within the VPC.
Help me figure out why my subnets aren't showing up correctly.
Your VPC foundation is set. Next up, you'll connect it to the internet by creating an Internet Gateway, a NAT Gateway, and the route tables that direct traffic between them.
Configure Internet Gateway, NAT Gateway, and Route Tables
Your VPC and subnets are in place, but right now nothing can reach the internet. Subnets are isolated by default.
In this step, you will create the networking components that control how traffic flows in and out of your VPC. Public subnets will get a direct path to the internet through an Internet Gateway. Private subnets will reach the internet (for updates and patches) through a NAT Gateway that hides their private IP addresses.
In this step, get ready to:
- Create and attach an Internet Gateway for public internet access.
- Set up public and private route tables with correct routing rules.
- Deploy a NAT Gateway so private instances can reach the internet securely.
Create and attach an Internet Gateway
An Internet Gateway is the component that connects your VPC to the public internet. Without it, even instances in public subnets cannot send or receive traffic from outside AWS.
- In the VPC Console left navigation panel, click Internet Gateways.
- Click Create internet gateway.
- Enter ABCEnergy-IGW in the Name tag field.
- Click Create internet gateway.
The Internet Gateway is now created but not yet connected to your VPC. You need to attach it.
- With ABCEnergy-IGW selected, click Actions.
- Select Attach to VPC.
- In the Available VPCs dropdown, select ABCEnergy-VPC.
- Click Attach internet gateway.
You should see the State change to Attached next to your Internet Gateway.
What does attaching an Internet Gateway do?
Attaching the Internet Gateway to your VPC makes it possible for resources inside the VPC to communicate with the public internet. It acts as a doorway, but traffic will only flow through it if a route table tells it to.
You will configure that route table next.
Create route tables and configure routing
Route tables are the traffic rules for your subnets. Each subnet can only follow one route table at a time, and the route table tells traffic where to go based on its destination.
You will create two route tables. The public one sends internet-bound traffic to the Internet Gateway. The private one will eventually send internet-bound traffic through the NAT Gateway (which you will create shortly).
- In the left navigation panel, click Route Tables.
- Click Create route table.
- Enter ABCEnergy-Public-RT as the Name.
- Select ABCEnergy-VPC in the VPC dropdown.
- Click Create route table.
Now add the internet route to this public route table.
- With ABCEnergy-Public-RT selected, click the Routes tab in the details pane below.
- Click Edit routes.
- Click Add route.
- Enter 0.0.0.0/0 in the Destination field.
- In the Target dropdown, select Internet Gateway, then select ABCEnergy-IGW.
- Click Save changes.
What does 0.0.0.0/0 mean?
The destination 0.0.0.0/0 is a catch-all route that matches any IP address not covered by a more specific route. It means "everything else goes here." Traffic destined for the VPC's own CIDR (10.0.0.0/16) still stays local. Only traffic headed outside the VPC follows this route to the Internet Gateway.
Next, associate this public route table with both public subnets.
- Click the Subnet associations tab.
- Click Edit subnet associations.
- Check the boxes next to Public-Subnet-1 and Public-Subnet-2.
- Click Save associations.
Now create the private route table. You will add its internet route after the NAT Gateway is ready.
- Click Route Tables in the left panel to return to the route tables list.
- Click Create route table.
- Enter ABCEnergy-Private-RT as the Name.
- Select ABCEnergy-VPC in the VPC dropdown.
- Click Create route table.
- Click the Subnet associations tab.
- Click Edit subnet associations.
- Check the boxes next to Private-Subnet-1 and Private-Subnet-2.
- Click Save associations.
Don't see your subnets in the association list?
Make sure you selected ABCEnergy-VPC when creating the route table. If you accidentally used a different VPC, the subnets from ABCEnergy-VPC will not appear. Delete the route table and recreate it with the correct VPC selected.
Help me troubleshoot my route table subnet associations.
Deploy a NAT Gateway
A NAT Gateway allows instances in private subnets to reach the internet (for example, to download software updates) without exposing them to inbound traffic from the internet. It translates private IP addresses to a public Elastic IP on the way out.
- In the left panel, click NAT Gateways.
- Click Create NAT gateway.
- Enter ABCEnergy-NAT in the Name field.
- In the Subnet dropdown, select Public-Subnet-1.
- Confirm the Connectivity type is set to Public.
- Click Allocate Elastic IP to assign a public IP address to the NAT Gateway.
- Click Create NAT gateway.
Why does the NAT Gateway go in a public subnet?
The NAT Gateway itself needs internet access so it can forward traffic on behalf of your private instances. By placing it in a public subnet (which routes through the Internet Gateway), it can reach the internet and relay responses back to the private subnet.
Wait for the NAT Gateway status to change from Pending to Available. This typically takes 1-2 minutes.
NAT Gateway costs money
The NAT Gateway charges $0.045 per hour from the moment it is created. Complete this project and clean up your resources promptly to keep costs minimal. You will delete the NAT Gateway in the Before You Go section.
Now that the NAT Gateway is available, add the internet route to your private route table.
- In the left panel, click Route Tables.
- Select ABCEnergy-Private-RT.
- Click the Routes tab, then click Edit routes.
- Click Add route.
- Enter 0.0.0.0/0 in the Destination field.
- In the Target dropdown, select NAT Gateway, then select ABCEnergy-NAT.
- Click Save changes.
How do the two route tables differ?
Both route tables send internet-bound traffic (0.0.0.0/0) somewhere, but the destination is different. The public route table sends traffic directly to the Internet Gateway. The private route table sends traffic to the NAT Gateway, which then forwards it to the Internet Gateway on behalf of the private instances.
This means private instances can make outbound requests, but nothing on the internet can initiate an inbound connection to them.
NAT Gateway stuck in Pending?
If the status does not change to Available after 3-4 minutes, try refreshing the page. If it still shows Pending, check that you selected a public subnet (one with a route to the Internet Gateway) and that an Elastic IP was allocated successfully.
Help me troubleshoot my NAT Gateway status.
Your network plumbing is complete. Traffic can now flow from public subnets to the internet directly, and from private subnets to the internet through the NAT Gateway. Next up, you will lock down access with Security Groups and Network ACLs.
Configure Security Groups and Network ACLs
Your VPC now has subnets, gateways, and route tables that control where traffic can flow. But routing alone doesn't decide who is allowed to reach your resources.
AWS provides two layers of network security: Security Groups (instance-level firewalls) and Network ACLs (subnet-level firewalls). In this step, you'll configure both to enforce least-privilege access between your public and private tiers.
In this step, get ready to:
- Create a Web Server Security Group that allows HTTP, HTTPS, and SSH traffic.
- Create a Database Security Group that only allows access from the web server.
- Configure a Network ACL to add a second layer of defense on public subnets.
Create the Web Server Security Group
A Security Group acts as a virtual firewall for individual instances. Your web server needs to accept HTTP and HTTPS traffic from the internet, plus SSH access from your computer for management.
- In the VPC Console left panel, click Security Groups.
- Click Create security group.
- Enter ABCEnergy-WebServer-SG in the Security group name field.
- Enter Allow HTTP, HTTPS, and SSH for web server in the Description field.
- In the VPC dropdown, select ABCEnergy-VPC.
Now add the inbound rules. Scroll down to the Inbound rules section and click Add rule three times to create three rule rows.
- For rule 1: set Type to HTTP. The port auto-fills to 80. Set Source to Anywhere-IPv4 (0.0.0.0/0).
- For rule 2: set Type to HTTPS. The port auto-fills to 443. Set Source to Anywhere-IPv4 (0.0.0.0/0).
- For rule 3: set Type to SSH. The port auto-fills to 22. Set Source to My IP from the dropdown.
Why restrict SSH to My IP?
Selecting My IP automatically fills in your current public IPv4 address with a /32 prefix. This means only your computer can SSH into the web server.
Setting SSH to 0.0.0.0/0 (anywhere) would expose your server to brute-force attacks from the entire internet. Least-privilege means only the people who need access get it.
- Leave the Outbound rules section at its default (all traffic allowed).
- Scroll to the bottom and click Create security group.
You should see a success banner confirming that your security group was created. The details page shows your three inbound rules.
Don't see ABCEnergy-VPC in the dropdown?
Make sure you're in the same AWS region where you created your VPC. Check the region selector in the top-right corner of the console.
Help me find my VPC when creating a security group.
Create the Database Security Group
Your database server should never be accessible from the public internet. It only needs to accept connections from the web server on the MySQL port, plus SSH from the web server for testing.
- In the left panel, click Security Groups again.
- Click Create security group.
- Enter ABCEnergy-Database-SG in the Security group name field.
- Enter Allow MySQL from web server only in the Description field.
- In the VPC dropdown, select ABCEnergy-VPC.
Scroll down to the Inbound rules section and click Add rule twice to create two rule rows.
- For rule 1: set Type to MYSQL/Aurora. The port auto-fills to 3306. In the Source field, type sg- and select ABCEnergy-WebServer-SG from the results.
- For rule 2: set Type to SSH. The port auto-fills to 22. In the Source field, type sg- and select ABCEnergy-WebServer-SG from the results.
Why reference a security group as the source?
Instead of specifying an IP address, you're telling AWS to allow traffic from any instance that belongs to ABCEnergy-WebServer-SG. This is more flexible than hardcoding IPs because it works even if you add more web servers later.
- Leave the Outbound rules section at its default (all traffic allowed).
- Click Create security group.
You should see a success banner. The details page shows two inbound rules, both sourced from your Web Server security group.
What is least-privilege access?
Least-privilege means granting only the minimum permissions needed. Your Database SG only accepts MySQL connections from the Web Server SG. No one else on the internet, or even in other parts of your VPC, can reach port 3306.
Configure Network ACLs for public subnets
Network ACLs operate at the subnet level, adding a second layer of defense in front of your Security Groups. Unlike Security Groups, NACLs are stateless. This means you need to explicitly allow return traffic (ephemeral ports) for connections to work.
Why use both Security Groups and NACLs?
Security Groups are stateful. If you allow inbound traffic, the response is automatically allowed out. NACLs are stateless. You must define rules in both directions.
Using both gives you defense in depth. If a Security Group rule is accidentally misconfigured, the NACL still blocks unauthorized traffic at the subnet boundary.
- In the VPC Console left panel, click Network ACLs.
- Click Create network ACL.
- Enter ABCEnergy-Public-NACL in the Name field.
- Select ABCEnergy-VPC from the VPC dropdown.
- Click Create network ACL.
Your new NACL starts by denying all traffic. You need to add specific allow rules. Select ABCEnergy-Public-NACL from the list, then configure its inbound rules.
- Click the Inbound rules tab.
- Click Edit inbound rules.
- Click Add new rule four times to create four rule rows.
Fill in each rule as follows:
- Rule 100: Type HTTP (80), Source 0.0.0.0/0, Action Allow.
- Rule 110: Type HTTPS (443), Source 0.0.0.0/0, Action Allow.
- Rule 120: Type SSH (22), Source 0.0.0.0/0, Action Allow.
- Rule 130: Type Custom TCP, Port range 1024-65535, Source 0.0.0.0/0, Action Allow.
- Click Save changes.
What are ephemeral ports?
When a client connects to your web server on port 80, the response goes back on a random high-numbered port (1024-65535) called an ephemeral port. Since NACLs are stateless, you must explicitly allow these return ports or your web server's responses will be blocked.
Now configure the outbound rules.
- Click the Outbound rules tab.
- Click Edit outbound rules.
- Click Add new rule three times to create three rule rows.
Fill in each outbound rule:
- Rule 100: Type HTTP (80), Destination 0.0.0.0/0, Action Allow.
- Rule 110: Type HTTPS (443), Destination 0.0.0.0/0, Action Allow.
- Rule 120: Type Custom TCP, Port range 1024-65535, Destination 0.0.0.0/0, Action Allow.
- Click Save changes.
Finally, associate this NACL with your public subnets.
- Click the Subnet associations tab.
- Click Edit subnet associations.
- Check the boxes for Public-Subnet-1 and Public-Subnet-2.
- Click Save changes.
Why leave private subnets on the default NACL?
The default NACL allows all traffic in and out. Since your Database Security Group already enforces least-privilege at the instance level (only MySQL from the Web SG), adding a restrictive NACL on private subnets would be redundant for this project.
The public NACL demonstrates how subnet-level filtering works as a second barrier in front of your Security Groups.
You should see both public subnets listed under the Subnet associations tab for your NACL.
Subnets not showing in the association list?
Each subnet can only be associated with one NACL at a time. If your subnets don't appear, they may already be associated with another custom NACL. Check that you're selecting subnets that belong to ABCEnergy-VPC.
Help me associate subnets with my NACL.
Your VPC now has two layers of network security in place. Security Groups protect individual instances with stateful rules. The public NACL adds a stateless subnet-level barrier. Next up, you'll launch EC2 instances into these subnets and test that your connectivity and security controls actually work.
Launch EC2 Instances and Test Connectivity
Your network security controls are in place. The Web Server security group allows HTTP, HTTPS, and SSH from trusted sources. The Database security group only permits MySQL traffic from the web tier.
Now it is time to prove this architecture actually works. You will launch two EC2 instances into your VPC and verify that traffic flows exactly as designed.
In this step, get ready to:
- Launch a public web server in Public-Subnet-1 with internet access.
- Launch a private database server in Private-Subnet-1 with no public IP.
- Test connectivity between tiers and to the internet.
Launch the web server
The web server sits in the public subnet, receives a public IP address, and is the entry point for external traffic into your VPC.
- Open the EC2 Console by navigating to https://console.aws.amazon.com/ec2/ in a new tab.
- Confirm you are in the same region where you created your VPC (e.g., us-east-1).
- Click Launch instances from the EC2 dashboard.
- Under Name and tags, enter ABCEnergy-WebServer as the name.
- Under Application and OS Images, choose Quick Start, select Amazon Linux, and confirm Amazon Linux 2023 AMI is selected (marked Free tier eligible).
- Under Instance type, select t2.micro (Free tier eligible). If t2.micro is unavailable in your region, choose t3.micro instead.
- Under Key pair (login), click Create new key pair.
- Enter ABCEnergy-Key as the key pair name.
- Set Key pair type to RSA and Private key file format to .pem.
- Click Create key pair. Your browser downloads the ABCEnergy-Key.pem file. Save it somewhere you can find it easily (e.g., your Downloads folder).
Do not lose this key file
AWS does not store your private key. If you lose this .pem file, you will not be able to SSH into your instances. Keep it safe.
- Under Network settings, click Edit.
- For VPC, select ABCEnergy-VPC.
- For Subnet, select Public-Subnet-1.
- For Auto-assign public IP, select Enable.
- For Firewall (security groups), choose Select existing security group.
- Select ABCEnergy-WebServer-SG from the dropdown.
- Leave all other settings at their defaults and click Launch instance.
What does this configuration do?
You placed the web server in a public subnet with a public IP and attached the WebServer security group. This means the instance can receive HTTP/HTTPS traffic from anywhere and SSH traffic from your IP address only.
The Internet Gateway and public route table you configured earlier handle outbound internet access for this instance.
Which EC2 free tier applies to you?
If you created your AWS account before July 15, 2025, t2.micro and t3.micro are free for 750 hours per month for 12 months.
If you created your account on or after July 15, 2025, free tier eligible types include t3.micro, t3.small, t4g.micro, and t4g.small under a 6-month credit model.
Launch the private server
The database server sits in a private subnet with no direct internet access. It can only be reached through the web server tier.
- Return to the EC2 dashboard and click Launch instances again.
- Under Name and tags, enter ABCEnergy-DBServer.
- Under Application and OS Images, choose Quick Start and confirm Amazon Linux 2023 AMI is selected.
- Under Instance type, select t2.micro (or t3.micro if unavailable).
- Under Key pair (login), select the existing ABCEnergy-Key you just created.
- Under Network settings, click Edit.
- For VPC, select ABCEnergy-VPC.
- For Subnet, select Private-Subnet-1.
- For Auto-assign public IP, select Disable.
- For Firewall (security groups), choose Select existing security group and select ABCEnergy-Database-SG.
- Leave all other settings at their defaults and click Launch instance.
How is this different from the web server?
The DB server has no public IP and uses the Database security group, which only allows MySQL (port 3306) and SSH (port 22) from the WebServer security group. It cannot be reached directly from the internet.
The private route table routes its internet-bound traffic through the NAT Gateway, so it can download updates without being publicly exposed.
- Navigate to Instances in the left panel of the EC2 Console.
- Wait for both ABCEnergy-WebServer and ABCEnergy-DBServer to show Instance state as Running and Status check as passed. This takes 1-2 minutes.
Note the IP addresses you will need
Select ABCEnergy-WebServer and note its Public IPv4 address from the Details tab. Then select ABCEnergy-DBServer and note its Private IPv4 address (it will be in the 10.0.3.x range). You will need both for the connectivity tests.
Test connectivity between your instances
You will now prove that your VPC networking works end-to-end. You will SSH into the web server, test internet access, hop to the private server, and verify security group enforcement.
First, set the correct permissions on your key file so SSH accepts it. Open a terminal on your local machine.
macOS
- Navigate to the folder where you downloaded ABCEnergy-Key.pem and restrict its permissions by running:
chmod 400 ABCEnergy-Key.pem
- Connect to your web server by running this command (replace the IP with your web server's public IPv4 address):
ssh -i ABCEnergy-Key.pem ec2-user@[[WEB_SERVER_IP="your web server public IPv4 address"]]
Type yes when prompted to confirm the host fingerprint.
Windows
Windows 10 and 11 include OpenSSH by default. Open Windows Terminal or PowerShell.
- Navigate to the folder where you downloaded ABCEnergy-Key.pem (e.g., your Downloads folder).
- Right-click ABCEnergy-Key.pem, select Properties, go to the Security tab, and click Advanced.
- Click Disable inheritance and choose Remove all inherited permissions from this object.
- Click Add, then Select a principal, enter your Windows username, and grant Read permissions only.
- Click OK to close all dialogs.
- Connect to your web server by running this command (replace the IP with your web server's public IPv4 address):
ssh -i ABCEnergy-Key.pem ec2-user@[[WEB_SERVER_IP="your web server public IPv4 address"]]
Type yes when prompted to confirm the host fingerprint.
Getting a permissions error?
If you see a warning mentioning an unprotected private key file, your key permissions are too open. Go back and follow the permissions step for your operating system above.
If you see Connection timed out, double-check that your Web Server security group allows SSH (port 22) from your current IP address. Your IP may have changed since you created the rule.
Need more help? Help me troubleshoot my SSH connection to the web server.
You should now see the Amazon Linux command prompt. You are inside your web server.
- Test that the web server can reach the internet (proving the Internet Gateway route works) by running:
ping -c 4 google.com
What should I see?
You should see 4 packets transmitted and 4 packets received with response times. This confirms your public route table is correctly sending traffic through the Internet Gateway.
Next, you need to reach the private DB server from the web server. To do this, copy your key file to the web server, then SSH from there.
- Type exit to return to your local machine.
- Copy your key file to the web server by running:
scp -i ABCEnergy-Key.pem ABCEnergy-Key.pem ec2-user@[[WEB_SERVER_IP="your web server public IPv4 address"]]:~/
- SSH back into the web server:
ssh -i ABCEnergy-Key.pem ec2-user@[[WEB_SERVER_IP="your web server public IPv4 address"]]
- Set permissions on the copied key and SSH into the DB server using its private IP:
chmod 400 ~/ABCEnergy-Key.pem
ssh -i ~/ABCEnergy-Key.pem ec2-user@[[DB_SERVER_PRIVATE_IP="your DB server private IPv4 address"]]
Type yes when prompted. You are now inside the private DB server.
Why can the web server reach the DB server?
The Database security group allows SSH (port 22) from the WebServer security group. Because your SSH session originates from the web server instance (which belongs to the WebServer SG), the connection is permitted.
If you tried to SSH directly from your laptop to the DB server's private IP, it would fail. There is no route from the internet to a private subnet, and the Database SG does not allow SSH from external IPs.
- Test that the DB server can reach the internet through the NAT Gateway by running:
ping -c 4 google.com
What does this prove?
The private server has no public IP, yet it can reach the internet. Traffic goes from Private-Subnet-1 to the private route table, which routes 0.0.0.0/0 to the NAT Gateway in Public-Subnet-1. The NAT Gateway then forwards the traffic through the Internet Gateway.
- Type exit to return to the web server.
- Test that the MySQL port (3306) is accessible from the web server to the DB server by running:
nc -zv [[DB_SERVER_PRIVATE_IP="your DB server private IPv4 address"]] 3306
What should I see?
You should see a message indicating the connection succeeded (or was refused by the host). The important thing is that the connection was not timed out or blocked by the security group.
Even though no MySQL service is running on the DB server, the security group allowed the TCP handshake on port 3306. This proves your Database SG rule works correctly.
Copying keys is simple but not production-safe
In a production environment, you would use SSH agent forwarding or AWS Systems Manager Session Manager instead of copying private keys to intermediate servers. For this learning project, the direct copy approach makes the security group behavior easier to observe.
- Type exit to disconnect from the web server and return to your local machine.
Ping or SSH to the DB server failed?
If ping from the DB server timed out, check that your private route table (ABCEnergy-Private-RT) has a 0.0.0.0/0 route pointing to the NAT Gateway. Also confirm the NAT Gateway status is Available.
If SSH from the web server to the DB server timed out, verify the Database security group has an inbound SSH rule with source set to the WebServer security group ID (not an IP address).
Still stuck? Help me debug connectivity between my public and private EC2 instances.
Your VPC architecture is fully operational. Every route, security group, and subnet is doing exactly what you designed it to do. Next up, you will enable VPC Flow Logs to monitor and analyze the traffic patterns you just created.
Secret mission
Enable VPC Flow Logs and Analyze Traffic
Your VPC is secure, but can you prove it? Enable VPC Flow Logs to monitor every packet flowing through your network. Then use CloudWatch Logs to identify which traffic is being accepted and which is being blocked by your security controls.
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. The NAT Gateway charges $0.045/hour from the moment it was created, so completing cleanup promptly will minimize cost.
Cost warning
Your NAT Gateway costs $0.045 per hour (approximately $1.08 per day). If left running, this adds up to roughly $32 per month. The Elastic IP is free while associated with the NAT Gateway, but will cost $0.005/hour if you delete the NAT Gateway without releasing the Elastic IP.
EC2 instances are free tier eligible (t2.micro, 750 hours/month for 12 months on accounts created before July 15, 2025). CloudWatch Logs ingestion from VPC Flow Logs incurs minimal cost.
Resources you used:
- ABCEnergy-NAT (NAT Gateway) with associated Elastic IP.
- ABCEnergy-WebServer and ABCEnergy-DBServer (EC2 instances).
- ABCEnergy-VPC (includes 4 subnets, 2 route tables, Internet Gateway, 2 security groups, and custom NACL).
- ABCEnergy-FlowLogs (CloudWatch Log group).
- ABCEnergy-VPC Flow Log.
- ABCEnergy-Key.pem (local key pair file).
Keep everything running
No action needed. Choose this if you plan to continue building on this VPC immediately.
- Your NAT Gateway will continue to charge $0.045/hour (~$32/month).
- EC2 instances remain free tier eligible (t2.micro).
- CloudWatch Logs will accumulate minimal ingestion charges from VPC Flow Logs.
Pause - I'll come back to this later
Stop your EC2 instances to save on compute charges while keeping all resources intact.
- Open the EC2 Console at https://console.aws.amazon.com/ec2/.
- In the navigation pane, choose Instances.
- Select ABCEnergy-WebServer, then choose Instance state, Stop instance. Confirm when prompted.
- Repeat for ABCEnergy-DBServer.
What still costs money when paused?
The NAT Gateway still charges $0.045/hour even when your instances are stopped. EBS storage remains at free tier levels. To fully stop charges, use the Delete tab.
Delete - I don't want to use this again
Remove all project resources and start fresh. Delete resources in this order to avoid dependency errors.
Step 1: Terminate both EC2 instances.
- Open the EC2 Console at https://console.aws.amazon.com/ec2/.
- In the navigation pane, choose Instances.
- Select ABCEnergy-WebServer, then choose Instance state, Terminate (delete) instance.
- Choose Terminate (delete) when prompted for confirmation.
- Repeat for ABCEnergy-DBServer.
Step 2: Delete the NAT Gateway.
- Open the VPC Console at https://console.aws.amazon.com/vpc/.
- In the navigation pane, choose NAT gateways.
- Select ABCEnergy-NAT, then choose Actions, Delete NAT gateway.
- When prompted for confirmation, enter delete and then choose Delete.
- Wait for the NAT Gateway status to change to Deleted (1-2 minutes).
Step 3: Release the Elastic IP address.
- In the VPC Console navigation pane, choose Elastic IPs.
- Select the Elastic IP that was associated with ABCEnergy-NAT, then choose Actions, Release Elastic IP addresses.
- When prompted, choose Release.
Step 4: Delete the VPC.
- In the VPC Console navigation pane, choose Your VPCs.
- Select ABCEnergy-VPC, then choose Actions, Delete VPC.
- Confirm the deletion when prompted. This automatically removes the subnets, route tables, Internet Gateway, security groups, and Network ACLs associated with the VPC.
Step 5: Delete the CloudWatch Log group.
- Open the CloudWatch Console at https://console.aws.amazon.com/cloudwatch/.
- In the navigation pane, choose Log groups.
- Select the ABCEnergy-FlowLogs log group, then choose Actions, Delete.
- Confirm the deletion when prompted.
What about the VPC Flow Log?
Flow logs for deleted VPCs are eventually automatically removed by AWS. Since you already deleted ABCEnergy-VPC in Step 4, the flow log configuration will be cleaned up automatically.
Step 6: Delete the local key pair file.
- Delete the ABCEnergy-Key.pem file from your computer. On macOS/Linux, run:
rm ~/Downloads/ABCEnergy-Key.pem
- On Windows, navigate to your Downloads folder in File Explorer, right-click ABCEnergy-Key.pem, and select Delete.
Nice Work!
Nice Work!
Nice work! You just designed and implemented a production-style secure network architecture on AWS for ABC Energy Ltd.
You've learned how to:
- Build a multi-tier VPC (10.0.0.0/16) with public and private subnets across two Availability Zones, connecting them to the internet through an Internet Gateway and NAT Gateway.
- Enforce least-privilege access using layered security controls: Security Groups restricting MySQL to the web tier only, and Network ACLs as a second layer of defense on public subnets.
- Launch EC2 instances across public and private tiers and verify end-to-end connectivity and security enforcement using SSH and network testing.
- Secret Mission: Enabled VPC Flow Logs to CloudWatch and analyzed traffic patterns to observe accepted and rejected flows between network tiers.
Ready to quiz yourself?