DEV Community

Cover image for Building Your Own Virtual Private Cloud (VPC) on Linux
Adenuga Israel Abimbola
Adenuga Israel Abimbola

Posted on

Building Your Own Virtual Private Cloud (VPC) on Linux

Have you ever wondered what really happens when you create a Virtual Private Cloud (VPC) on AWS or GCP?
Behind the glossy dashboards and checkboxes, it’s all Linux, namespaces, bridges, and routing tables quietly working together.

In this guide, you’ll build your own local version of a cloud VPC.
You’ll use Linux network namespaces to create isolated environments, bridges to connect them, and iptables to manage NAT and firewall behavior.
And to tie it all together, you’ll run a small Python controller that automates the whole thing for you.

By the time you’re done, you’ll understand how cloud networking actually works, not just what buttons to click.


Project Overview

We’ll be using a simple setup called Bimbo VPC Controller.
It’s a command-line utility that lets you create virtual networks, connect them, enforce rules, and then clean them up again — all on your local machine.

Here’s the structure of the project folder:

/vpcctl-stage-4
│
├── demo.sh          # Runs the full demo automatically
├── policy.json      # Contains firewall and access policies
├── vpcctl.py        # Main Python controller script
└── README.md        # Documentation
Enter fullscreen mode Exit fullscreen mode

Architecture Overview

Let’s break down how the system fits together.

Each VPC is represented as a network namespace.
Within each VPC, there are two subnets — one public and one private — each connected to its own Linux bridge.
The bridges are connected to your host interface (like ens5) through veth pairs.
NAT and firewall rules are applied using iptables.

Here’s a simple sketch of what that looks like:

                +-------------------+
                |   VPC Namespace   |
                |  (vpc1 / vpc2)    |
                +---------+---------+
                          |
                     veth pair
                          |
                +---------+---------+
                |   Linux Bridge    |
                |  (br-vpc1-pub)    |
                +---------+---------+
                          |
                 Public / Private Subnets
                          |
                +---------+---------+
                |  NAT / Firewall   |
                | (iptables rules)  |
                +---------+---------+
                          |
                        Internet
Enter fullscreen mode Exit fullscreen mode

So when you create VPC1, you’re really creating a namespace with its own virtual network and routing.
It behaves just like an AWS VPC, only it’s running on your laptop.


Setting Up

First, clone the project from GitHub and move into the directory:

git clone https://github.com/<your-username>/vpcctl-stage-4.git
cd vpcctl-stage-4
Enter fullscreen mode Exit fullscreen mode

Make the scripts executable so they can run directly:

chmod +x demo.sh vpcctl.py
Enter fullscreen mode Exit fullscreen mode

If you’d like to make the Python script available globally, create a symbolic link:

sudo ln -s "$(pwd)/vpcctl.py" /usr/local/bin/vpcctl
Enter fullscreen mode Exit fullscreen mode

Now, install the required dependencies:

sudo apt update
sudo apt install -y iproute2 iptables curl netcat python3
Enter fullscreen mode Exit fullscreen mode

You’re ready to go.


Running the Demo

The easiest way to see everything in action is by running the demo script.
It handles creation, configuration, and cleanup automatically.

sudo ./demo.sh
Enter fullscreen mode Exit fullscreen mode

This will:

  • Create two VPCs (vpc1 and vpc2),
  • Add public and private subnets to each,
  • Launch small web servers inside them,
  • Enable NAT on the public subnets,
  • Apply firewall policies,
  • Test connectivity and isolation,
  • Then tear everything down.

You can watch every step unfold in your terminal as it happens.


Command Line Usage

If you’d rather control things manually, you can use the vpcctl commands yourself.

Create a VPC

sudo vpcctl create vpc1 --cidr 10.0.0.0/16
Enter fullscreen mode Exit fullscreen mode

This creates a Linux namespace named vpc1 and assigns it a network range.

Add Subnets

sudo vpcctl add-subnet vpc1 public --cidr 10.0.1.0/24
sudo vpcctl add-subnet vpc1 private --cidr 10.0.2.0/24
Enter fullscreen mode Exit fullscreen mode

Each subnet gets its own bridge, connected through a veth pair.
This is how communication inside the VPC happens.

Launch a Web Server

sudo vpcctl launch-http vpc1 public --port 80
Enter fullscreen mode Exit fullscreen mode

Starts a lightweight Python HTTP server inside the namespace.
You can test it with curl from another namespace later.

Apply a Firewall Policy

sudo vpcctl apply-policy policy.json
Enter fullscreen mode Exit fullscreen mode

The controller reads your policy file and uses iptables to allow or block specific traffic.

Peer Two VPCs

sudo vpcctl peer vpc1 vpc2
Enter fullscreen mode Exit fullscreen mode

This connects vpc1 and vpc2 through a virtual link so they can route traffic to each other.


Testing and Validation

After you’ve run the demo or created things manually, it’s time to verify everything is working as expected.

1. Connectivity Test Within a VPC

From the public subnet:

sudo ip netns exec vpc1-pub ping -c 2 10.0.2.1
Enter fullscreen mode Exit fullscreen mode

This should succeed, confirming that the subnets in the same VPC can communicate.

2. NAT Test

From the public subnet:

sudo ip netns exec vpc1-pub curl http://example.com
Enter fullscreen mode Exit fullscreen mode

This should work because NAT is enabled for the public subnet.

From the private subnet:

sudo ip netns exec vpc1-priv curl http://example.com
Enter fullscreen mode Exit fullscreen mode

This should fail — private subnets are isolated from the internet by design.

3. Isolation Test Between VPCs

Before peering:

sudo ip netns exec vpc1-pub ping -c 2 10.1.1.1
Enter fullscreen mode Exit fullscreen mode

This should fail, since vpc1 and vpc2 have no route between them.

After peering:

sudo ip netns exec vpc1-pub ping -c 2 10.1.1.1
Enter fullscreen mode Exit fullscreen mode

This should now succeed.
You’ve just simulated cross-VPC communication.


Firewall and Policy Test

Let’s edit the policy file:

{
  "vpc1": {
    "allow": ["80/tcp"],
    "deny": ["22/tcp"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Apply it using:

sudo vpcctl apply-policy policy.json
Enter fullscreen mode Exit fullscreen mode

Now test:

sudo ip netns exec vpc2-pub nc -vz 10.0.1.1 80
sudo ip netns exec vpc2-pub nc -vz 10.0.1.1 22
Enter fullscreen mode Exit fullscreen mode

The first should connect, the second should fail.
That’s your firewall doing its job.


Cleaning Up

When you’re done experimenting, you can safely delete everything and return your system to normal.

sudo vpcctl delete vpc1
sudo vpcctl delete vpc2
Enter fullscreen mode Exit fullscreen mode

Or simply use the demo’s built-in cleanup command:

sudo ./demo.sh clean
Enter fullscreen mode Exit fullscreen mode

This removes:

  • All network namespaces
  • All bridges and veth pairs
  • All iptables rules
  • All logs and state files

Clean, complete, and ready for another experiment.


Wrapping Up

You’ve just built a fully functional cloud-style network stack — using nothing but Linux.
You saw how namespaces create isolation, how bridges connect subnets, and how iptables acts as your NAT gateway and firewall.

This project gives you more than a working script — it gives you intuition.
You now understand what happens when AWS says “launch VPC,” “add subnet,” or “enable NAT.”

And the best part?
You built it all locally, from the ground up.


:)

Top comments (0)