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
- 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
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}")
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:
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!
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
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
- 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.
- 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!
- 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!)
- 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:
- Troubleshooting Docker
Now I understand what this actually does
docker network inspect bridge
And this makes sense
docker run --network=host
- Kubernetes Networking
CNI plugins are doing what I just built
apiVersion: v1
kind: NetworkPolicy
- 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)