Building a Production-Grade AWS VPC

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 NameAZTypeCIDR
aws-prod-example-subnet-public1-eu-central-1aeu-central-1aPublic10.0.1.0/24
aws-prod-example-subnet-public2-eu-central-1beu-central-1bPublic10.0.2.0/24
aws-prod-example-subnet-private1-eu-central-1aeu-central-1aPrivate10.0.10.0/24
aws-prod-example-subnet-private2-eu-central-1beu-central-1bPrivate10.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:

  1. 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.

  2. 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.

  3. Associate this route table with both private subnets.

Route Table NameAttached SubnetsRouting Config
aws-prod-example-rtb-publicPublic1 & Public20.0.0.0/0 → IGW
aws-prod-example-rtb-private1-eu-central-1aPrivate1 (eu-central-1a)0.0.0.0/0 → NAT Gateway
aws-prod-example-rtb-private2-eu-central-1bPrivate2 (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:

  1. Connect to the Bastion Host:

    • Make sure your local machine has the private key (.pem).

    • Connect using:

  2. 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:

  1. SSH into the public EC2 instance from the bastin-host:

  2. Run a basic Python web server:

  3. Make sure port 8000 is allowed in the security group (which I already did earlier).

  4. 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!

10
Subscribe to my newsletter

Read articles from Amey Dharmadhikari directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Amey Dharmadhikari
Amey Dharmadhikari