Building a Production-Grade AWS VPC

Table of contents
- Tools & Technologies Used
- Project Overview
- Step-by-Step Implementation
- 1. Create a Custom VPC
- 2. Create Subnets (Public & Private) in Two AZs
- 3. Create and Attach an Internet Gateway
- 4. Create Route Tables and Configure Routes
- 5. Create a NAT Gateway
- 6. Security Group Configuration
- 7. Launch EC2 Instances
- 8. Accessing Private Instance via Bastion Host (Jump Box)
- 9. Set Up a Simple HTTP Server on Public EC2 Instance
- Final Network Flow Summary:
- Let’s Chat!
Recently, I built a real-world AWS networking setup to create a production grade VPC. This article is a walkthrough of how I set up a fully functional Virtual Private Cloud (VPC) on AWS, including subnets, route tables, gateways, and security configurations—all from scratch.
Tools & Technologies Used
Here’s what I used during this project:
Amazon Web Services (AWS)
VPC (Virtual Private Cloud)
Subnets (Public & Private)
Internet Gateway
Route Tables
Security Groups & Network ACLs
EC2 Instances
NAT Gateway
Project Overview
The objective of this project was to simulate a production-like AWS network infrastructure, where public-facing resources (like a web server) are securely separated from internal ones (like a database).
We designed a multi-AZ (Availability Zone) architecture with both public and private subnets, allowing safe internet access and internal communication.
Step-by-Step Implementation
Here’s how I went about building the architecture:
1. Create a Custom VPC
Start by creating a dedicated VPC to define your own IP range and network settings.
Steps:
Go to the VPC Dashboard in AWS.
Click Create VPC → Choose “VPC only”.
Provide a Name tag (e.g.,
aws-prod-example
).Set the IPv4 CIDR block to
10.0.0.0/16
.Enable DNS hostname and DNS resolution.
Click Create VPC.
2. Create Subnets (Public & Private) in Two AZs
I created 4 subnets (2 public, 2 private), spread across eu-central-1a
and eu-central-1b
:
Steps:
Navigate to Subnets > Create Subnet.
Select the VPC you just created.
Choose an Availability Zone and give the subnet a name.
Subnet Name | AZ | Type | CIDR |
aws-prod-example-subnet-public1-eu-central-1a | eu-central-1a | Public | 10.0.1.0/24 |
aws-prod-example-subnet-public2-eu-central-1b | eu-central-1b | Public | 10.0.2.0/24 |
aws-prod-example-subnet-private1-eu-central-1a | eu-central-1a | Private | 10.0.10.0/24 |
aws-prod-example-subnet-private2-eu-central-1b | eu-central-1b | Private | 10.0.20.0/24 |
This setup enables high availability and segregation of external/internal traffic.
3. Create and Attach an Internet Gateway
Allows resources in public subnets to access the internet.
Steps:
Go to Internet Gateways > Create Internet Gateway.
Name it (e.g.,
aws-prod-example-igw
), then create.NAT Gateways (for each AZ):
aws-prod-example-nat-public1-eu-central-1a
aws-prod-example-nat-public2-eu-central-1b
After creation, click Attach to VPC and choose your custom VPC.
4. Create Route Tables and Configure Routes
Route tables define how traffic is directed in and out of subnets.
Steps:
Public Route Table:
Create a new route table (e.g.,
Public-RT
), associate it with the VPC.Under Routes, add
0.0.0.0/0
→ target: Internet Gateway.Associate this route table with both public subnets.
Private Route Table:
Create another route table (e.g.,
Private-RT
), associate it with the VPC.Initially leave it without internet access — we’ll modify this after setting up the NAT Gateway.
Associate this route table with both private subnets.
Route Table Name | Attached Subnets | Routing Config |
aws-prod-example-rtb-public | Public1 & Public2 | 0.0.0.0/0 → IGW |
aws-prod-example-rtb-private1-eu-central-1a | Private1 (eu-central-1a) | 0.0.0.0/0 → NAT Gateway |
aws-prod-example-rtb-private2-eu-central-1b | Private2 (eu-central-1b) | 0.0.0.0/0 → NAT Gateway |
5. Create a NAT Gateway
Allows instances in private subnets to access the internet (e.g., for software updates) without being publicly exposed.
Steps:
Go to NAT Gateways > Create NAT Gateway.
Select a public subnet (e.g., Public-Subnet-A).
Allocate or use an existing Elastic IP.
Name and create the NAT Gateway.
Go back to the Private Route Table, and add a new route:
0.0.0.0/0
→ target: NAT Gateway.
6. Security Group Configuration
Security Group Name:
aws-prod-example
Inbound Rules:
SSH (TCP 22) from anywhere
0.0.0.0/0
HTTP (TCP 80) from anywhere
0.0.0.0/0
Custom TCP (Port 8000) from anywhere
0.0.0.0/0
7. Launch EC2 Instances
EC2 instances were launched in private subnets and added to the load balancer’s target group to handle traffic.
These instances can only be reached through the ALB, improving security and scalability.
8. Accessing Private Instance via Bastion Host (Jump Box)
Since the private subnet has no direct internet access, I used a bastion host (deployed in a public subnet) to access the EC2 instance in the private subnet.
Steps:
Connect to the Bastion Host:
Make sure your local machine has the private key (
.pem
).Connect using:
From the Bastion, SSH into Private EC2:
Use the private IP of the internal EC2 instance:
9. Set Up a Simple HTTP Server on Public EC2 Instance
After launching the EC2 instance in the private subnet, I installed a basic HTTP server to verify if the load balancer and security groups were working as expected.
Steps:
SSH into the public EC2 instance from the bastin-host:
Run a basic Python web server:
Make sure port 8000 is allowed in the security group (which I already did earlier).
Then, visit the Load Balancer DNS URL in your browser:
aws-prod-example-1405715954.eu-central-1.elb.amazonaws.com
This confirmed that the ALB was correctly forwarding requests to the EC2 instance on port 8000.
Final Network Flow Summary:
Users access the application via ALB → forwarded to public EC2 (HTTP server on port 8000).
I access the private EC2 instance through a bastion host in the public subnet.
The private EC2 instance can reach the internet via the NAT Gateway, but is not publicly accessible itself.
Let’s Chat!
Tried something similar? Got questions or suggestions? Drop a comment—I’d love to hear your thoughts!
Subscribe to my newsletter
Read articles from Amey Dharmadhikari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
