DEV Community

Sheriff Ademoye
Sheriff Ademoye

Posted on

🌐 Build Your Own Virtual Private Cloud (VPC) on Linux

I recreated AWS VPC functionality on a single Linux machine using network namespaces, bridges, and iptables. No cloud providers, no Docker - just pure Linux networking. All 13 tests passed, and I learned more about networking in one week than in months of theory.

πŸ€” The Challenge
As part of the HNG DevOps Internship Stage 4, I was given this challenge:

"Build your own Virtual Private Cloud (VPC) using Linux networking primitives. It must support subnets, routing, NAT gateways, VPC isolation, peering, and security groups."

My first reaction? "Wait, I thought VPCs were a cloud thing?"
Turns out, AWS VPC, Azure VNet, and GCP VPC are all built on the same Linux networking concepts I was about to implement. This project would show me what's really happening under the hood.

🎯 What I Set Out to Build
Imagine you're building a banking application. You need:

A web frontend - accessible from the internet
An API backend - talks to frontend and database
A database - completely isolated from the internet

In AWS, you'd create a VPC with public and private subnets. I was going to build exactly that - but on my laptop.
The Architecture
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ My Linux Machine β”‚
β”‚ (eth0 β†’ Internet) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Linux Bridge β”‚ ← My "VPC Router"
β”‚ (10.0.1.1) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Public Subnetβ”‚ β”‚ Private Subnet β”‚
β”‚ (10.0.1.2) β”‚ β”‚ (10.0.2.2) β”‚
β”‚ Internet: βœ“ β”‚ β”‚ Internet: βœ— β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ› οΈ The Building Blocks

  1. Network Namespaces = Subnets Think of network namespaces as "mini virtual machines" for networking. Each namespace has its own:

Network interfaces
IP addresses
Routing tables
Firewall rules

# Create an isolated network environment
sudo ip netns add my-subnet

# It's completely isolated from the host
sudo ip netns exec my-subnet ip addr

# Only shows loopback interface!

This is how Docker containers get isolated networking!

2. Linux Bridges = VPC Routers

A bridge is like a virtual network switch. It connects multiple network interfaces together.

# Create a bridge (my VPC router)

sudo ip link add br-myvpc type bridge
sudo ip link set br-myvpc up
sudo ip addr add 10.0.1.1/24 dev br-myvpc

This bridge becomes the gateway for all my subnets.

3. veth Pairs = Virtual Network Cables

veth pairs are like virtual ethernet cables - always come in pairs, what goes in one end comes out the other.

# Create a virtual cable
sudo ip link add veth0 type veth peer name veth1

# One end goes in the namespace (subnet)
sudo ip link set veth1 netns my-subnet

# Other end connects to the bridge (router)
sudo ip link set veth0 master br-myvpc

This is the same concept Docker uses to connect containers!

4. iptables = NAT Gateway + Firewall

To give subnets internet access, I needed NAT (Network Address Translation):

# Enable IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1

# Add NAT rule (the magic that gives internet access)
sudo iptables -t nat -A POSTROUTING \
  -s 10.0.1.0/24 -o eth0 -j MASQUERADE

# Allow forwarding

sudo iptables -A FORWARD \
  -s 10.0.1.2/32 -o eth0 -j ACCEPT

What this does: Changes the source IP from 10.0.1.2 (private) to my laptop's public IP when packets go to the internet.

πŸ’» Building the CLI Tool
I automated everything into a Python CLI tool called vpcctl. Here's a glimpse:

### Creating a VPC

Enter fullscreen mode Exit fullscreen mode

def create_vpc(name, cidr):
bridge = f"br-{name}"

# Create bridge
subprocess.run(["ip", "link", "add", bridge, "type", "bridge"])
subprocess.run(["ip", "link", "set", bridge, "up"])
subprocess.run(["ip", "addr", "add", cidr, "dev", bridge])

print(f"βœ“ VPC '{name}' created with bridge {bridge}")
Enter fullscreen mode Exit fullscreen mode

Create a VPC

sudo ./vpcctl.py create-vpc --name production --cidr 10.0.1.1/24

Add public subnet (with internet)

sudo ./vpcctl.py add-subnet \
--vpc production \
--subnet web \
--ip 10.0.1.2 \
--gateway 10.0.1.1 \
--nat

Add private subnet (no internet)

sudo ./vpcctl.py add-subnet \
--vpc production \
--subnet database \
--ip 10.0.2.2 \
--gateway 10.0.2.1



# The Challenges 

Challenge #1: iptables Rules Were Invisible

I was adding iptables rules, seeing success messages, but when I checked:

Enter fullscreen mode Exit fullscreen mode

sudo iptables -L FORWARD

Chain FORWARD (policy ACCEPT)

(Empty!)


The problem: I was suppressing errors with stderr=subprocess.DEVNULL. The rules were failing silently!

The fix: Removed the suppression, saw the real error, fixed the issue.
Lesson learned: Never hide errors during development. Debug first, clean up later.

Challenge #2: VPC Isolation Not Working
My two VPCs could communicate even though they shouldn't!

Enter fullscreen mode Exit fullscreen mode

This should fail but didn't

sudo ip netns exec vpc1-subnet ping 10.1.1.2

64 bytes from 10.1.1.2 βœ— (shouldn't work!)

The problem: My ACCEPT rules were too broad. They were matching ALL traffic, not just internet traffic.

The fix: Made ACCEPT rules specific to the internet interface:

Before (matches everything)

iptables -A FORWARD -s 10.0.1.2/32 -j ACCEPT

After (only matches internet traffic)

iptables -A FORWARD -s 10.0.1.2/32 -o eth0 -j ACCEPT

Lesson learned: Firewall rules need to be specific. General rules create security holes.

Challenge #3: WSL2 iptables Issues

On Windows WSL2, my iptables commands weren't working at all!

The fix:

# Switch to iptables-legacy
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
Enter fullscreen mode Exit fullscreen mode

Lesson learned: Different environments have different quirks. Always test in your target environment.

πŸŽ‰ The Results
After days of debugging, I finally got all 13 tests passing:
[1] VPC Creation βœ“ PASS
[2] Subnet Creation βœ“ PASS
[3] List VPCs and Subnets βœ“ PASS
[4] Intra-VPC Communication βœ“ PASS
[5] Public Subnet Internet Access βœ“ PASS
[6] Private Subnet Blocked from Internet βœ“ PASS
[7] VPC Isolation βœ“ PASS
[8] VPC Peering Creation βœ“ PASS
[9] Cross-VPC Communication After Peering βœ“ PASS
[10] App Deployment βœ“ PASS
[11] Access App from Host βœ“ PASS
[12] Firewall Rules Application βœ“ PASS
[13] Configuration Export βœ“ PASS

Result: 13/13 (100% Success Rate!) πŸŽ‰
What Works:
βœ… VPC isolation - Different VPCs can't communicate by default
βœ… NAT gateway - Public subnets have internet, private don't
βœ… VPC peering - Can enable controlled cross-VPC communication
βœ… Security groups - Firewall rules work perfectly
βœ… Clean teardown - No orphaned resources

🧠 What I Actually Learned
Technical Skills

Network Namespaces - The foundation of container networking
Linux Bridges - How virtual routers work
iptables - NAT, forwarding, and firewall rules
veth Pairs - Virtual network connections
IP Routing - How packets move between networks

Bigger Insights

  1. Cloud providers aren't magic AWS VPC, Azure VNet - they're all using these same Linux primitives under the hood. Now when I use cloud VPCs, I know what's really happening.
  2. Docker and Kubernetes make more sense now Every Docker container uses network namespaces. Kubernetes CNI plugins are just automating what I built manually. Suddenly, all those networking concepts in the docs make sense!
  3. Debugging is a superpower I spent more time debugging than coding. But each bug taught me something:

Read error messages carefully
Test in isolation
Don't hide errors during development
Check assumptions (my iptables rules existed, but weren't working!)

  1. Documentation is hard but essential Writing this blog post helped me understand my own project better. Explaining concepts forced me to really understand them.

πŸŽ“ For Anyone Wanting to Try This
Start Here

Learn the basics first

What is a network namespace?
What is a Linux bridge?
How does NAT work?

Build incrementally

Create one namespace
Connect it to a bridge
Add internet access (NAT)
Then add isolation, peering, etc.

Test everything

Write tests before adding features
Test in isolation
Verify expected failures (isolation should block traffic!)

Don't hide errors

Let yourself see what's breaking
Read error messages
Google is your friend

Resources That Helped Me

Linux Network Namespaces Man Page
iptables Tutorial
How Docker Networking Works
Stack Overflow (obviously πŸ˜„)

πŸ’‘ Real-World Applications
This project isn't just academic. Understanding these concepts helps with:

  1. Troubleshooting Docker

Now I understand what this actually does

docker network inspect bridge

And this makes sense

docker run --network=host

  1. Kubernetes Networking

CNI plugins are doing what I just built

apiVersion: v1
kind: NetworkPolicy

  1. Cloud VPC Design

I now understand why this matters

aws ec2 create-vpc --cidr-block 10.0.0.0/16

πŸš€ The Code
Full project on GitHub: github.com/Sheviantos1/hng13-devops-stage4-vpc

Quick Start

Clone the repo

git clone https://github.com/Sheviantos1/hng13-devops-stage4-vpc.git
cd hng13-devops-stage4-vpc

Run the test suite

./test.sh

Try it yourself

sudo ./vpcctl.py create-vpc --name test --cidr 10.0.1.1/24

🎯 Key Takeaways

Cloud services use the same Linux primitives you can learn and use yourself
Network isolation is fundamental to modern infrastructure
iptables is powerful but needs careful, specific rules
Building from scratch teaches you way more than using abstractions
Debugging skills are more valuable than coding speed

πŸ™ Acknowledgments

HNG Internship for the challenging project
The Linux networking community for amazing documentation
Stack Overflow for saving me countless times
Everyone who helped debug those iptables issues

πŸ’¬ Let's Connect
If you found this helpful or have questions:

GitHub: @Sheviantos1
Twitter: [@sheviantos]
LinkedIn: [@Ademoye-sheriff]

Building something similar? Drop a comment - I'd love to hear about your approach!

Top comments (0)